<!DOCTYPE HTML>
<html lang="en">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="AverageJoe&#39;s Blog">
    <meta name="description" content="this is my secret garden where I sow my inspirations.">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>AverageJoe&#39;s Blog</title>
    <link rel="icon" type="image/png" href="/favicon.png">

    <link rel="stylesheet" type="text/css" href="/libs/awesome/css/all.css">
    <link rel="stylesheet" type="text/css" href="/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/css/my.css">

    <script src="/libs/jquery/jquery.min.js"></script>
<meta name="generator" content="Hexo 5.0.0"><link rel="alternate" href="/atom.xml" title="AverageJoe's Blog" type="application/atom+xml">
</head>


<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/" class="waves-effect waves-light">
                    
                    <img src="/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">AverageJoe&#39;s Blog</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>Index</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>Tags</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>Categories</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/archives" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>Archives</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>About</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/contact" class="waves-effect waves-light">
      
      <i class="fas fa-comments" style="zoom: 0.6;"></i>
      
      <span>Contact</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/friends" class="waves-effect waves-light">
      
      <i class="fas fa-address-book" style="zoom: 0.6;"></i>
      
      <span>Friends</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="Search" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">AverageJoe&#39;s Blog</div>
        <div class="logo-desc">
            
            this is my secret garden where I sow my inspirations.
            
        </div>
    </div>

    

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			Index
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			Tags
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			Categories
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/archives" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			Archives
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			About
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/contact" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-comments"></i>
			
			Contact
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/friends" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-address-book"></i>
			
			Friends
		</a>
          
        </li>
        
        
    </ul>
</div>


        </div>

        
    </nav>

</header>

    
<script src="/libs/cryptojs/crypto-js.min.js"></script>
<script>
    (function() {
        let pwd = '';
        if (pwd && pwd.length > 0) {
            if (pwd !== CryptoJS.SHA256(prompt('请输入访问本文章的密码')).toString(CryptoJS.enc.Hex)) {
                alert('密码错误，将返回主页！');
                location.href = '/';
            }
        }
    })();
</script>




<div class="bg-cover pd-header post-cover" style="background-image: url('/medias/featureimages/0.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title"></h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="post-container content">

    
    <link rel="stylesheet" href="/libs/tocbot/tocbot.css">
<style>
    #articleContent h1::before,
    #articleContent h2::before,
    #articleContent h3::before,
    #articleContent h4::before,
    #articleContent h5::before,
    #articleContent h6::before {
        display: block;
        content: " ";
        height: 100px;
        margin-top: -100px;
        visibility: hidden;
    }

    #articleContent :focus {
        outline: none;
    }

    .toc-fixed {
        position: fixed;
        top: 64px;
    }

    .toc-widget {
        width: 345px;
        padding-left: 20px;
    }

    .toc-widget .toc-title {
        margin: 35px 0 15px 0;
        padding-left: 17px;
        font-size: 1.5rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    .toc-widget ol {
        padding: 0;
        list-style: none;
    }

    #toc-content {
        height: calc(100vh - 250px);
        overflow: auto;
    }

    #toc-content ol {
        padding-left: 10px;
    }

    #toc-content ol li {
        padding-left: 10px;
    }

    #toc-content .toc-link:hover {
        color: #42b983;
        font-weight: 700;
        text-decoration: underline;
    }

    #toc-content .toc-link::before {
        background-color: transparent;
        max-height: 25px;

        position: absolute;
        right: 23.5vw;
        display: block;
    }

    #toc-content .is-active-link {
        color: #42b983;
    }

    #floating-toc-btn {
        position: fixed;
        right: 15px;
        bottom: 76px;
        padding-top: 15px;
        margin-bottom: 0;
        z-index: 998;
    }

    #floating-toc-btn .btn-floating {
        width: 48px;
        height: 48px;
    }

    #floating-toc-btn .btn-floating i {
        line-height: 48px;
        font-size: 1.4rem;
    }
</style>
<div class="row">
    <div id="main-content" class="col s12 m12 l9">
        <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                          <div class="article-tag">
                            <span class="chip bg-color">No tag</span>
                          </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>Publish Date:&nbsp;&nbsp;
                    2018-05-28
                </div>
                

                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-check fa-fw"></i>Update Date:&nbsp;&nbsp;
                    2018-05-28
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-file-word fa-fw"></i>Word Count:&nbsp;&nbsp;
                    13k
                </div>
                

                
                <div class="info-break-policy">
                    <i class="far fa-clock fa-fw"></i>Read Times:&nbsp;&nbsp;
                    58 Min
                </div>
                

                
                    <div id="busuanzi_container_page_pv" class="info-break-policy">
                        <i class="far fa-eye fa-fw"></i>Read Count:&nbsp;&nbsp;
                        <span id="busuanzi_value_page_pv"></span>
                    </div>
				
            </div>
        </div>
        <hr class="clearfix">
        <div class="card-content article-card-content">
            <div id="articleContent">
                <h1 id="0-学习目标"><a href="#0-学习目标" class="headerlink" title="0.学习目标"></a>0.学习目标</h1><ul>
<li>使用资料搭建后台系统</li>
<li>会使用nginx进行反向代理</li>
<li>实现商品分类查询功能</li>
<li>掌握cors解决跨域</li>
<li>实现品牌查询功能</li>
</ul>
<h1 id="1-使用域名访问本地项目"><a href="#1-使用域名访问本地项目" class="headerlink" title="1.使用域名访问本地项目"></a>1.使用域名访问本地项目</h1><h2 id="1-1-统一环境"><a href="#1-1-统一环境" class="headerlink" title="1.1.统一环境"></a>1.1.统一环境</h2><p>我们现在访问页面使用的是：<a target="_blank" rel="noopener" href="http://localhost:9001/">http://localhost:9001</a></p>
<p>有没有什么问题？</p>
<p>实际开发中，会有不同的环境：</p>
<ul>
<li>开发环境：自己的电脑</li>
<li>测试环境：提供给测试人员使用的环境</li>
<li>预发布环境：数据是和生成环境的数据一致，运行最新的项目代码进去测试</li>
<li>生产环境：项目最终发布上线的环境</li>
</ul>
<p>如果不同环境使用不同的ip去访问，可能会出现一些问题。为了保证所有环境的一致，我们会在各种环境下都使用域名来访问。</p>
<p>我们将使用以下域名：</p>
<ul>
<li>主域名是：<a target="_blank" rel="noopener" href="http://www.leyou.com,/">www.leyou.com，</a></li>
<li>管理系统域名：manage.leyou.com</li>
<li>网关域名：api.leyou.com</li>
<li>…</li>
</ul>
<p>但是最终，我们希望这些域名指向的还是我们本机的某个端口。</p>
<p>那么，当我们在浏览器输入一个域名时，浏览器是如何找到对应服务的ip和端口的呢？</p>
<h2 id="1-2-域名解析"><a href="#1-2-域名解析" class="headerlink" title="1.2.域名解析"></a>1.2.域名解析</h2><p>一个域名一定会被解析为一个或多个ip。这一般会包含两步：</p>
<ul>
<li><p>本地域名解析</p>
<p>浏览器会首先在本机的hosts文件中查找域名映射的IP地址，如果查找到就返回IP ，没找到则进行域名服务器解析，一般本地解析都会失败，因为默认这个文件是空的。</p>
<ul>
<li>Windows下的hosts文件地址：C:/Windows/System32/drivers/etc/hosts</li>
<li>Linux下的hosts文件所在路径： /etc/hosts </li>
</ul>
<p>样式：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># My hosts</span><br><span class="line">127.0.0.1 localhost</span><br><span class="line">0.0.0.0 account.jetbrains.com</span><br><span class="line">127.0.0.1 www.xmind.net</span><br></pre></td></tr></table></figure>
</li>
<li><p>域名服务器解析</p>
<p>本地解析失败，才会进行域名服务器解析，域名服务器就是网络中的一台计算机，里面记录了所有注册备案的域名和ip映射关系，一般只要域名是正确的，并且备案通过，一定能找到。</p>
</li>
</ul>
<h2 id="1-3-解决域名解析问题"><a href="#1-3-解决域名解析问题" class="headerlink" title="1.3.解决域名解析问题"></a>1.3.解决域名解析问题</h2><p>我们不可能去购买一个域名，因此我们可以伪造本地的hosts文件，实现对域名的解析。修改本地的host为：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1 api.leyou.com</span><br><span class="line">127.0.0.1 manage.leyou.com</span><br></pre></td></tr></table></figure>

<p>这样就实现了域名的关系映射了。</p>
<p>每次在C盘寻找hosts文件并修改是非常麻烦的，给大家推荐一个快捷修改host的工具，在课前资料中可以找到：</p>
<p> <img src="assets/1526014883706.png" alt="1526014883706"></p>
<p>效果：</p>
<p> <img src="assets/1526015022365.png" alt="1526015022365"></p>
<p>我们添加了两个映射关系：</p>
<ul>
<li>127.0.0.1 api.leyou.com ：我们的网关Zuul</li>
<li>127.0.0.1 manage.leyou.com：我们的后台系统地址</li>
</ul>
<p>现在，ping一下域名试试是否畅通：</p>
<p> <img src="assets/1526015211298.png" alt="1526015211298"></p>
<p>OK！</p>
<h2 id="1-4-nginx解决端口问题"><a href="#1-4-nginx解决端口问题" class="headerlink" title="1.4.nginx解决端口问题"></a>1.4.nginx解决端口问题</h2><p>虽然域名解决了，但是现在如果我们要访问，还得自己加上端口：<code>http://manage.taotao.com:9001</code>。</p>
<p>这就不够优雅了。我们希望的是直接域名访问：<code>http://manage.taotao.com</code>。这种情况下端口默认是80，如何才能把请求转移到9001端口呢？</p>
<p>这里就要用到反向代理工具：Nginx</p>
<h3 id="1-4-1-什么是Nginx"><a href="#1-4-1-什么是Nginx" class="headerlink" title="1.4.1.什么是Nginx"></a>1.4.1.什么是Nginx</h3><p><img src="assets/1526187409033.png" alt="1526187409033"></p>
<p>NIO：not-blocking-io 非阻塞IO</p>
<p>BIO：blocking-IO 阻塞IO</p>
<p>nginx可以作为web服务器，但更多的时候，我们把它作为网关，因为它具备网关必备的功能：</p>
<ul>
<li>反向代理</li>
<li>负载均衡</li>
<li>动态路由</li>
<li>请求过滤</li>
</ul>
<h3 id="1-4-2-nginx作为web服务器"><a href="#1-4-2-nginx作为web服务器" class="headerlink" title="1.4.2.nginx作为web服务器"></a>1.4.2.nginx作为web服务器</h3><p>Web服务器分2类：</p>
<ul>
<li><p>web应用服务器，如：</p>
<ul>
<li>tomcat</li>
<li>resin</li>
<li>jetty</li>
</ul>
</li>
<li><p>web服务器，如：</p>
<ul>
<li>Apache 服务器</li>
<li>Nginx</li>
<li>IIS</li>
</ul>
</li>
</ul>
<p>区分：web服务器不能解析jsp等页面，只能处理js、css、html等静态资源。<br>并发：web服务器的并发能力远高于web应用服务器。</p>
<p>Nginx + tomcat</p>
<h3 id="1-4-3-nginx作为反向代理"><a href="#1-4-3-nginx作为反向代理" class="headerlink" title="1.4.3.nginx作为反向代理"></a>1.4.3.nginx作为反向代理</h3><p>什么是反向代理？</p>
<ul>
<li>代理：通过客户机的配置，实现让一台服务器代理客户机，客户的所有请求都交给代理服务器处理。</li>
<li>反向代理：用一台服务器，代理真实服务器，用户访问时，不再是访问真实服务器，而是代理服务器。</li>
</ul>
<p>nginx可以当做反向代理服务器来使用：</p>
<ul>
<li>我们需要提前在nginx中配置好反向代理的规则，不同的请求，交给不同的真实服务器处理</li>
<li>当请求到达nginx，nginx会根据已经定义的规则进行请求的转发，从而实现路由功能</li>
</ul>
<p>利用反向代理，就可以解决我们前面所说的端口问题，如图</p>
<p><img src="assets/1526016663674.png" alt="1526016663674"></p>
<h3 id="1-4-4-安装和使用"><a href="#1-4-4-安装和使用" class="headerlink" title="1.4.4.安装和使用"></a>1.4.4.安装和使用</h3><blockquote>
<h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3></blockquote>
<p>安装非常简单，把课前资料提供的nginx直接解压即可，绿色免安装，舒服！</p>
<p><img src="assets/0C36B84E.gif" alt="img"> </p>
<p>我们在本地安装一台nginx：</p>
<p> <img src="assets/1526016829605.png" alt="1526016829605"></p>
<p>目录结构：</p>
<p> <img src="assets/1526188477802.png" alt="1526188477802"></p>
<blockquote>
<h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3></blockquote>
<p>nginx可以通过命令行来启动，操作命令：</p>
<ul>
<li>启动：<code>start nginx.exe</code></li>
<li>停止：<code>nginx.exe -s stop</code></li>
<li>重新加载：<code>nginx.exe -s reload</code></li>
</ul>
<blockquote>
<h3 id="反向代理配置"><a href="#反向代理配置" class="headerlink" title="反向代理配置"></a>反向代理配置</h3></blockquote>
<p>示例：</p>
<p> <img src="assets/1526188831504.png" alt="1526188831504"></p>
<p>nginx中的每个server就是一个反向代理配置，可以有多个server</p>
<p>完整配置：</p>
<figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">#user  nobody;</span></span><br><span class="line"><span class="attribute">worker_processes</span>  <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="section">events</span> &#123;</span><br><span class="line">    <span class="attribute">worker_connections</span>  <span class="number">1024</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="section">http</span> &#123;</span><br><span class="line">    <span class="attribute">include</span>       mime.types;</span><br><span class="line">    <span class="attribute">default_type</span>  application/octet-stream;</span><br><span class="line">    <span class="attribute">sendfile</span>        <span class="literal">on</span>;</span><br><span class="line">   </span><br><span class="line">    <span class="attribute">keepalive_timeout</span>  <span class="number">65</span>;</span><br><span class="line"></span><br><span class="line">    <span class="attribute">gzip</span>  <span class="literal">on</span>;</span><br><span class="line">    <span class="section">server</span> &#123;</span><br><span class="line">        <span class="attribute">listen</span>       <span class="number">80</span>;</span><br><span class="line">        <span class="attribute">server_name</span>  manage.leyou.com;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-Host <span class="variable">$host</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-Server <span class="variable">$host</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">location</span> / &#123;</span><br><span class="line">            <span class="attribute">proxy_pass</span> http://127.0.0.1:9001;</span><br><span class="line">            <span class="attribute">proxy_connect_timeout</span> <span class="number">600</span>;</span><br><span class="line">            <span class="attribute">proxy_read_timeout</span> <span class="number">600</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="section">server</span> &#123;</span><br><span class="line">        <span class="attribute">listen</span>       <span class="number">80</span>;</span><br><span class="line">        <span class="attribute">server_name</span>  api.leyou.com;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-Host <span class="variable">$host</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-Server <span class="variable">$host</span>;</span><br><span class="line">        <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">location</span> / &#123;</span><br><span class="line">            <span class="attribute">proxy_pass</span> http://127.0.0.1:10010;</span><br><span class="line">            <span class="attribute">proxy_connect_timeout</span> <span class="number">600</span>;</span><br><span class="line">            <span class="attribute">proxy_read_timeout</span> <span class="number">600</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="1-5-测试"><a href="#1-5-测试" class="headerlink" title="1.5.测试"></a>1.5.测试</h2><p>启动nginx，然后用域名访问后台管理系统：</p>
<p><img src="assets/1526017010289.png" alt="1526017010289"></p>
<p>现在实现了域名访问网站了，中间的流程是怎样的呢？</p>
<p><img src="assets/1526189945180.png" alt="1526189945180"></p>
<ol>
<li><p>浏览器准备发起请求，访问<a target="_blank" rel="noopener" href="http://mamage.leyou.com,但需要进行域名解析/">http://mamage.leyou.com，但需要进行域名解析</a></p>
</li>
<li><p>优先进行本地域名解析，因为我们修改了hosts，所以解析成功，得到地址：127.0.0.1</p>
</li>
<li><p>请求被发往解析得到的ip，并且默认使用80端口：<a target="_blank" rel="noopener" href="http://127.0.0.1/">http://127.0.0.1:80</a></p>
<p>本机的nginx一直监听80端口，因此捕获这个请求</p>
</li>
<li><p>nginx中配置了反向代理规则，将manage.leyou.com代理到127.0.0.1:9001，因此请求被转发</p>
</li>
<li><p>后台系统的webpack server监听的端口是9001，得到请求并处理，完成后将响应返回到nginx</p>
</li>
<li><p>nginx将得到的结果返回到浏览器</p>
</li>
</ol>
<h1 id="2-实现商品分类查询"><a href="#2-实现商品分类查询" class="headerlink" title="2.实现商品分类查询"></a>2.实现商品分类查询</h1><p>商城的核心自然是商品，而商品多了以后，肯定要进行分类，并且不同的商品会有不同的品牌信息，其关系如图所示：</p>
<p><img src="assets/1525999005260.png" alt="1525999005260"></p>
<ul>
<li>一个商品分类下有很多商品</li>
<li>一个商品分类下有很多品牌</li>
<li>而一个品牌，可能属于不同的分类</li>
<li>一个品牌下也会有很多商品</li>
</ul>
<p>因此，我们需要依次去完成：商品分类、品牌、商品的开发。</p>
<h2 id="2-1-导入数据"><a href="#2-1-导入数据" class="headerlink" title="2.1.导入数据"></a>2.1.导入数据</h2><p>首先导入课前资料提供的sql：</p>
<p> <img src="assets/1525999677772.png" alt="1525999677772"></p>
<p>我们先看商品分类表：</p>
<p> <img src="assets/1525999774439.png" alt="1525999774439"></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE &#96;tb_category&#96; (</span><br><span class="line">  &#96;id&#96; bigint(20) NOT NULL AUTO_INCREMENT COMMENT &#39;类目id&#39;,</span><br><span class="line">  &#96;name&#96; varchar(20) NOT NULL COMMENT &#39;类目名称&#39;,</span><br><span class="line">  &#96;parent_id&#96; bigint(20) NOT NULL COMMENT &#39;父类目id,顶级类目填0&#39;,</span><br><span class="line">  &#96;is_parent&#96; tinyint(1) NOT NULL COMMENT &#39;是否为父节点，0为否，1为是&#39;,</span><br><span class="line">  &#96;sort&#96; int(4) NOT NULL COMMENT &#39;排序指数，越小越靠前&#39;,</span><br><span class="line">  PRIMARY KEY (&#96;id&#96;),</span><br><span class="line">  KEY &#96;key_parent_id&#96; (&#96;parent_id&#96;) USING BTREE</span><br><span class="line">) ENGINE&#x3D;InnoDB AUTO_INCREMENT&#x3D;1424 DEFAULT CHARSET&#x3D;utf8 COMMENT&#x3D;&#39;商品类目表，类目和商品(spu)是一对多关系，类目与品牌是多对多关系&#39;;</span><br></pre></td></tr></table></figure>

<p>因为商品分类会有层级关系，因此这里我们加入了<code>parent_id</code>字段，对本表中的其它分类进行自关联。</p>
<h2 id="2-2-页面实现"><a href="#2-2-页面实现" class="headerlink" title="2.2.页面实现"></a>2.2.页面实现</h2><h3 id="2-2-1-页面分析"><a href="#2-2-1-页面分析" class="headerlink" title="2.2.1.页面分析"></a>2.2.1.页面分析</h3><p>首先我们看下要实现的效果：</p>
<p><img src="assets/1525999250932.png" alt="1525999250932"></p>
<p>商品分类之间是会有层级关系的，采用树结构去展示是最直观的方式。</p>
<p>一起来看页面，对应的是/pages/item/Category.vue：</p>
<p> <img src="assets/1526000313361.png" alt="1526000313361"></p>
<p>页面模板：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">v-card</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">v-flex</span> <span class="attr">xs12</span> <span class="attr">sm10</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">v-tree</span> <span class="attr">url</span>=<span class="string">&quot;/item/category/list&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:treeData</span>=<span class="string">&quot;treeData&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:isEdit</span>=<span class="string">&quot;isEdit&quot;</span></span></span><br><span class="line"><span class="tag">                @<span class="attr">handleAdd</span>=<span class="string">&quot;handleAdd&quot;</span></span></span><br><span class="line"><span class="tag">                @<span class="attr">handleEdit</span>=<span class="string">&quot;handleEdit&quot;</span></span></span><br><span class="line"><span class="tag">                @<span class="attr">handleDelete</span>=<span class="string">&quot;handleDelete&quot;</span></span></span><br><span class="line"><span class="tag">                @<span class="attr">handleClick</span>=<span class="string">&quot;handleClick&quot;</span></span></span><br><span class="line"><span class="tag">                /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">v-flex</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">v-card</span>&gt;</span></span><br></pre></td></tr></table></figure>

<ul>
<li><p><code>v-card</code>：卡片，是vuetify中提供的组件，提供一个悬浮效果的面板，一般用来展示一组数据。</p>
<p><img src="assets/1526000692741.png" alt="1526000692741"></p>
</li>
<li><p><code>v-flex</code>：布局容器，用来控制响应式布局。与BootStrap的栅格系统类似，整个屏幕被分为12格。我们可以控制所占的格数来控制宽度：</p>
<p><img src="assets/1526001573140.png" alt="1526001573140"></p>
<p>本例中，我们用<code>sm10</code>控制在小屏幕及以上时，显示宽度为10格</p>
</li>
<li><p><code>v-tree</code>：树组件。Vuetify并没有提供树组件，这个是我们自己编写的自定义组件：</p>
<p> <img src="assets/1526001762446.png" alt="1526001762446"></p>
<p>里面涉及一些vue的高级用法，大家暂时不要关注其源码，会用即可。</p>
</li>
</ul>
<h3 id="2-2-2-树组件的用法"><a href="#2-2-2-树组件的用法" class="headerlink" title="2.2.2.树组件的用法"></a>2.2.2.树组件的用法</h3><p>也可参考课前资料中的：《自定义Vue组件的用法.md》</p>
<p>这里我贴出树组件的用法指南。</p>
<blockquote>
<p>属性列表：</p>
</blockquote>
<table>
<thead>
<tr>
<th align="left">属性名称</th>
<th align="left">说明</th>
<th align="left">数据类型</th>
<th align="left">默认值</th>
</tr>
</thead>
<tbody><tr>
<td align="left">url</td>
<td align="left">用来加载数据的地址，即延迟加载</td>
<td align="left">String</td>
<td align="left">-</td>
</tr>
<tr>
<td align="left">isEdit</td>
<td align="left">是否开启树的编辑功能</td>
<td align="left">boolean</td>
<td align="left">false</td>
</tr>
<tr>
<td align="left">treeData</td>
<td align="left">整颗树数据，这样就不用远程加载了</td>
<td align="left">Array</td>
<td align="left">-</td>
</tr>
</tbody></table>
<p>这里推荐使用url进行延迟加载，<strong>每当点击父节点时，就会发起请求，根据父节点id查询子节点信息</strong>。</p>
<p>当有treeData属性时，就不会触发url加载</p>
<p>远程请求返回的结果格式：</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">    &#123; </span><br><span class="line">        <span class="attr">&quot;id&quot;</span>: <span class="number">74</span>,</span><br><span class="line">        <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;手机&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;parentId&quot;</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">&quot;isParent&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">&quot;sort&quot;</span>: <span class="number">2</span></span><br><span class="line">    &#125;,</span><br><span class="line">     &#123; </span><br><span class="line">        <span class="attr">&quot;id&quot;</span>: <span class="number">75</span>,</span><br><span class="line">        <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;家用电器&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;parentId&quot;</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">&quot;isParent&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">&quot;sort&quot;</span>: <span class="number">3</span></span><br><span class="line">    &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure>



<blockquote>
<p>事件：</p>
</blockquote>
<table>
<thead>
<tr>
<th align="left">事件名称</th>
<th align="left">说明</th>
<th align="left">回调参数</th>
</tr>
</thead>
<tbody><tr>
<td align="left">handleAdd</td>
<td align="left">新增节点时触发，isEdit为true时有效</td>
<td align="left">新增节点node对象，包含属性：name、parentId和sort</td>
</tr>
<tr>
<td align="left">handleEdit</td>
<td align="left">当某个节点被编辑后触发，isEdit为true时有效</td>
<td align="left">被编辑节点的id和name</td>
</tr>
<tr>
<td align="left">handleDelete</td>
<td align="left">当删除节点时触发，isEdit为true时有效</td>
<td align="left">被删除节点的id</td>
</tr>
<tr>
<td align="left">handleClick</td>
<td align="left">点击某节点时触发</td>
<td align="left">被点击节点的node对象,包含全部信息</td>
</tr>
</tbody></table>
<blockquote>
<p>完整node的信息</p>
</blockquote>
<p>回调函数中返回完整的node节点会包含以下数据：</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    <span class="attr">&quot;id&quot;</span>: <span class="number">76</span>, <span class="comment">// 节点id</span></span><br><span class="line">    <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;手机&quot;</span>, <span class="comment">// 节点名称</span></span><br><span class="line">    <span class="attr">&quot;parentId&quot;</span>: <span class="number">75</span>, <span class="comment">// 父节点id</span></span><br><span class="line">    <span class="attr">&quot;isParent&quot;</span>: <span class="literal">false</span>, <span class="comment">// 是否是父节点</span></span><br><span class="line">    <span class="attr">&quot;sort&quot;</span>: <span class="number">1</span>, <span class="comment">// 顺序</span></span><br><span class="line">    <span class="attr">&quot;path&quot;</span>: [<span class="string">&quot;手机&quot;</span>, <span class="string">&quot;手机通讯&quot;</span>, <span class="string">&quot;手机&quot;</span>] <span class="comment">// 所有父节点的名称数组</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="2-3-实现功能"><a href="#2-3-实现功能" class="headerlink" title="2.3.实现功能"></a>2.3.实现功能</h2><h3 id="2-3-1-url异步请求"><a href="#2-3-1-url异步请求" class="headerlink" title="2.3.1.url异步请求"></a>2.3.1.url异步请求</h3><p>给大家的页面中，treeData是假数据，我们删除数据treeData属性，只保留url看看会发生什么：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">v-tree</span> <span class="attr">url</span>=<span class="string">&quot;/item/category/list&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">:isEdit</span>=<span class="string">&quot;isEdit&quot;</span></span></span><br><span class="line"><span class="tag">        @<span class="attr">handleAdd</span>=<span class="string">&quot;handleAdd&quot;</span></span></span><br><span class="line"><span class="tag">        @<span class="attr">handleEdit</span>=<span class="string">&quot;handleEdit&quot;</span></span></span><br><span class="line"><span class="tag">        @<span class="attr">handleDelete</span>=<span class="string">&quot;handleDelete&quot;</span></span></span><br><span class="line"><span class="tag">        @<span class="attr">handleClick</span>=<span class="string">&quot;handleClick&quot;</span></span></span><br><span class="line"><span class="tag">        /&gt;</span></span><br></pre></td></tr></table></figure>

<p>刷新页面，可以看到：</p>
<p><img src="assets/1526004282868.png" alt="1526004282868"></p>
<p>页面中的树没有了，并且发起了一条请求：<a target="_blank" rel="noopener" href="http://localhost/api/item/category/list?pid=0">http://localhost/api/item/category/list?pid=0</a> </p>
<p>大家可能会觉得很奇怪，我们明明是使用的相对路径，讲道理发起的请求地址应该是：</p>
<p><a target="_blank" rel="noopener" href="http://manage.leyou.com/item/category/list">http://manage.leyou.com/item/category/list</a></p>
<p>但实际却是：</p>
<p><a target="_blank" rel="noopener" href="http://localhost/api/item/category/list?pid=0">http://localhost/api/item/category/list?pid=0</a> </p>
<p>这是因为，我们有一个全局的配置文件，对所有的请求路径进行了约定：</p>
<p> <img src="assets/1526005059829.png" alt="1526005059829"></p>
<p> <img src="assets/1526005071153.png" alt="1526005071153"></p>
<p>路径是localhost，并且默认加上了/api的前缀，这恰好与我们的网关设置匹配，我们只需要把地址改成网关的地址即可,因为我们使用了nginx反向代理，这里可以写域名：</p>
<p> <img src="assets/1526017217473.png" alt="1526017217473"></p>
<p>再次查看页面，发现地址已经变成了正确的地址了：</p>
<p> <img src="assets/1526017265625.png" alt="1526017265625"></p>
<p>接下来，我们要做的事情就是编写后台接口，返回对应的数据即可。</p>
<h3 id="2-3-2-实体类"><a href="#2-3-2-实体类" class="headerlink" title="2.3.2.实体类"></a>2.3.2.实体类</h3><p>在<code>ly-item-interface</code>中添加category实体类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Table(name=&quot;tb_category&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Category</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Id</span></span><br><span class="line">    <span class="meta">@GeneratedValue(strategy=GenerationType.IDENTITY)</span></span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> Long parentId;</span><br><span class="line">    <span class="keyword">private</span> Boolean isParent;</span><br><span class="line">    <span class="keyword">private</span> Integer sort;</span><br><span class="line">    <span class="comment">// getter和setter略</span></span><br><span class="line">    <span class="comment">// 注意isParent的get和set方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>需要注意的是，这里要用到jpa的注解，因此我们在<code>ly-item-iterface</code>中添加jpa依赖</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>javax.persistence<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>persistence-api<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>结构：</p>
<p> <img src="assets/1526006869782.png" alt="1526006869782"></p>
<h3 id="2-3-3-controller"><a href="#2-3-3-controller" class="headerlink" title="2.3.3.controller"></a>2.3.3.controller</h3><p>编写一个controller一般需要知道四个内容：</p>
<ul>
<li>请求方式：决定我们用GetMapping还是PostMapping</li>
<li>请求路径：决定映射路径</li>
<li>请求参数：决定方法的参数</li>
<li>返回值结果：决定方法的返回值</li>
</ul>
<p>在刚才页面发起的请求中，我们就能得到绝大多数信息：</p>
<p> <img src="assets/1527473096007.png" alt="1527473096007"></p>
<ul>
<li><p>请求方式：Get</p>
</li>
<li><p>请求路径：/api/item/category/list。其中/api是网关前缀，/item是网关的路由映射，真实的路径应该是/category/list</p>
</li>
<li><p>请求参数：pid=0，根据tree组件的说明，应该是父节点的id，第一次查询为0，那就是查询一级类目</p>
</li>
<li><p>返回结果：？？</p>
<p>根据前面tree组件的用法我们知道，返回的应该是json数组：</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">    &#123; </span><br><span class="line">        <span class="attr">&quot;id&quot;</span>: <span class="number">74</span>,</span><br><span class="line">        <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;手机&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;parentId&quot;</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">&quot;isParent&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">&quot;sort&quot;</span>: <span class="number">2</span></span><br><span class="line">    &#125;,</span><br><span class="line">     &#123; </span><br><span class="line">        <span class="attr">&quot;id&quot;</span>: <span class="number">75</span>,</span><br><span class="line">        <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;家用电器&quot;</span>,</span><br><span class="line">        <span class="attr">&quot;parentId&quot;</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">&quot;isParent&quot;</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">&quot;sort&quot;</span>: <span class="number">3</span></span><br><span class="line">    &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<p>对应的java类型可以是List集合，里面的元素就是类目对象了。</p>
</li>
</ul>
<p>controller代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;category&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CategoryController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> CategoryService categoryService;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据父节点查询商品类目</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> pid</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;list&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> ResponseEntity&lt;List&lt;Category&gt;&gt; queryByParentId(</span><br><span class="line">            <span class="meta">@RequestParam(value = &quot;pid&quot;, defaultValue = &quot;0&quot;)</span> Long pid) &#123;</span><br><span class="line">        List&lt;Category&gt; list = <span class="keyword">this</span>.categoryService.queryListByParent(pid);</span><br><span class="line">        <span class="keyword">if</span> (list == <span class="keyword">null</span> || list.size() &lt; <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> ResponseEntity&lt;&gt;(HttpStatus.NOT_FOUND);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> ResponseEntity.ok(list);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="2-3-4-service"><a href="#2-3-4-service" class="headerlink" title="2.3.4.service"></a>2.3.4.service</h3><p>一般service层我们会定义接口和实现类，不过这里我们就偷懒一下，直接写实现类了：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CategoryService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> CategoryMapper categoryMapper;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> List&lt;Category&gt; <span class="title">queryListByParent</span><span class="params">(Long pid)</span> </span>&#123;</span><br><span class="line">        Category category = <span class="keyword">new</span> Category();</span><br><span class="line">        category.setParentId(pid);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.categoryMapper.select(category);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="2-3-5-mapper"><a href="#2-3-5-mapper" class="headerlink" title="2.3.5.mapper"></a>2.3.5.mapper</h3><p>我们使用通用mapper来简化开发：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">CategoryMapper</span> <span class="keyword">extends</span> <span class="title">Mapper</span>&lt;<span class="title">Category</span>&gt; </span>&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>要注意，我们并没有在mapper接口上声明@Mapper注解，那么mybatis如何才能找到接口呢？</p>
<p>我们在启动类上添加一个扫描包功能：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableDiscoveryClient</span></span><br><span class="line"><span class="meta">@MapperScan(&quot;com.leyou.item.mapper&quot;)</span> <span class="comment">// 扫描mapper包</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LyItemService</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SpringApplication.run(LyItemService.class, args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="2-3-6-启动并测试"><a href="#2-3-6-启动并测试" class="headerlink" title="2.3.6.启动并测试"></a>2.3.6.启动并测试</h3><p>我们不经过网关，直接访问：</p>
<p> <img src="assets/1526009785484.png" alt="1526009785484"></p>
<p>然后试试网关是否畅通：</p>
<p>  <img src="assets/1526017422684.png" alt="1526017422684"></p>
<p>一切OK！</p>
<p>然后刷新页面查看：</p>
<p><img src="assets/1526017362418.png" alt="1526017362418"></p>
<p>发现报错了！</p>
<p>浏览器直接访问没事，但是这里却报错，什么原因？</p>
<h2 id="2-4-跨域问题"><a href="#2-4-跨域问题" class="headerlink" title="2.4.跨域问题"></a>2.4.跨域问题</h2><h3 id="2-4-1-什么是跨域"><a href="#2-4-1-什么是跨域" class="headerlink" title="2.4.1.什么是跨域"></a>2.4.1.什么是跨域</h3><p>跨域是指跨域名的访问，以下情况都属于跨域：</p>
<table>
<thead>
<tr>
<th>跨域原因说明</th>
<th>示例</th>
</tr>
</thead>
<tbody><tr>
<td>域名不同</td>
<td><code>www.jd.com</code> 与 <code>www.taobao.com</code></td>
</tr>
<tr>
<td>域名相同，端口不同</td>
<td><code>www.jd.com:8080</code> 与 <code>www.jd.com:8081</code></td>
</tr>
<tr>
<td>二级域名不同</td>
<td><code>item.jd.com</code> 与 <code>miaosha.jd.com</code></td>
</tr>
</tbody></table>
<p>如果<strong>域名和端口都相同，但是请求路径不同</strong>，不属于跨域，如：</p>
<p><code>www.jd.com/item</code> </p>
<p><code>www.jd.com/goods</code></p>
<p>而我们刚才是从<code>manage.leyou.com</code>去访问<code>api.leyou.com</code>，这属于二级域名不同，跨域了。</p>
<h3 id="2-4-2-为什么有跨域问题？"><a href="#2-4-2-为什么有跨域问题？" class="headerlink" title="2.4.2.为什么有跨域问题？"></a>2.4.2.为什么有跨域问题？</h3><p>跨域不一定会有跨域问题。</p>
<p>因为跨域问题是浏览器对于ajax请求的一种安全限制：<strong>一个页面发起的ajax请求，只能是于当前页同域名的路径</strong>，这能有效的阻止跨站攻击。</p>
<p>因此：<strong>跨域问题 是针对ajax的一种限制</strong>。</p>
<p>但是这却给我们的开发带来了不变，而且在实际生成环境中，肯定会有很多台服务器之间交互，地址和端口都可能不同，怎么办？</p>
<h3 id="2-4-3-解决跨域问题的方案"><a href="#2-4-3-解决跨域问题的方案" class="headerlink" title="2.4.3.解决跨域问题的方案"></a>2.4.3.解决跨域问题的方案</h3><p>目前比较常用的跨域解决方案有3种：</p>
<ul>
<li><p>Jsonp</p>
<p>最早的解决方案，利用script标签可以跨域的原理实现。</p>
<p>限制：</p>
<ul>
<li>需要服务的支持</li>
<li>只能发起GET请求</li>
</ul>
</li>
<li><p>nginx反向代理</p>
<p>思路是：利用nginx反向代理把跨域为不跨域，支持各种请求方式</p>
<p>缺点：需要在nginx进行额外配置，语义不清晰</p>
</li>
<li><p>CORS</p>
<p>规范化的跨域请求解决方案，安全可靠。</p>
<p>优势：</p>
<ul>
<li>在服务端进行控制是否允许跨域，可自定义规则</li>
<li>支持各种请求方式</li>
</ul>
<p>缺点：</p>
<ul>
<li>会产生额外的请求</li>
</ul>
</li>
</ul>
<p>我们这里会采用cors的跨域方案。</p>
<h2 id="2-5-cors解决跨域"><a href="#2-5-cors解决跨域" class="headerlink" title="2.5.cors解决跨域"></a>2.5.cors解决跨域</h2><h3 id="2-5-1-什么是cors"><a href="#2-5-1-什么是cors" class="headerlink" title="2.5.1.什么是cors"></a>2.5.1.什么是cors</h3><p>CORS是一个W3C标准，全称是”跨域资源共享”（Cross-origin resource sharing）。</p>
<p>它允许浏览器向跨源服务器，发出<a target="_blank" rel="noopener" href="http://www.ruanyifeng.com/blog/2012/09/xmlhttprequest_level_2.html"><code>XMLHttpRequest</code></a>请求，从而克服了AJAX只能<a target="_blank" rel="noopener" href="http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html">同源</a>使用的限制。</p>
<p>CORS需要浏览器和服务器同时支持。目前，所有浏览器都支持该功能，IE浏览器不能低于IE10。</p>
<ul>
<li><p>浏览器端：</p>
<p>目前，所有浏览器都支持该功能（IE10以下不行）。整个CORS通信过程，都是浏览器自动完成，不需要用户参与。</p>
</li>
<li><p>服务端：</p>
<p>CORS通信与AJAX没有任何差别，因此你不需要改变以前的业务逻辑。只不过，浏览器会在请求中携带一些头信息，我们需要以此判断是否运行其跨域，然后在响应头中加入一些信息即可。这一般通过过滤器完成即可。</p>
</li>
</ul>
<h3 id="2-5-2-原理有点复杂"><a href="#2-5-2-原理有点复杂" class="headerlink" title="2.5.2.原理有点复杂"></a>2.5.2.原理有点复杂</h3><p>浏览器会将ajax请求分为两类，其处理方案略有差异：简单请求、特殊请求。</p>
<h4 id="简单请求"><a href="#简单请求" class="headerlink" title="简单请求"></a>简单请求</h4><p>只要同时满足以下两大条件，就属于简单请求。：</p>
<p>（1) 请求方法是以下三种方法之一：</p>
<ul>
<li>HEAD</li>
<li>GET</li>
<li>POST</li>
</ul>
<p>（2）HTTP的头信息不超出以下几种字段：</p>
<ul>
<li>Accept</li>
<li>Accept-Language</li>
<li>Content-Language</li>
<li>Last-Event-ID</li>
<li>Content-Type：只限于三个值<code>application/x-www-form-urlencoded</code>、<code>multipart/form-data</code>、<code>text/plain</code></li>
</ul>
<p>当浏览器发现发现的ajax请求是简单请求时，会在请求头中携带一个字段：<code>Origin</code>.</p>
<p> <img src="assets/1526019242125.png" alt="1526019242125"></p>
<p>Origin中会指出当前请求属于哪个域（协议+域名+端口）。服务会根据这个值决定是否允许其跨域。</p>
<p>如果服务器允许跨域，需要在返回的响应头中携带下面信息：</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Access-Control-Allow-Origin</span>: http://manage.leyou.com</span><br><span class="line"><span class="attribute">Access-Control-Allow-Credentials</span>: true</span><br><span class="line"><span class="attribute">Content-Type</span>: text/html; charset=utf-8</span><br></pre></td></tr></table></figure>

<ul>
<li>Access-Control-Allow-Origin：可接受的域，是一个具体域名或者*，代表任意</li>
<li>Access-Control-Allow-Credentials：是否允许携带cookie，默认情况下，cors不会携带cookie，除非这个值是true</li>
</ul>
<p>注意：</p>
<p>如果跨域请求要想操作cookie，需要满足3个条件：</p>
<ul>
<li>服务的响应头中需要携带Access-Control-Allow-Credentials并且为true。</li>
<li>浏览器发起ajax需要指定withCredentials 为true</li>
<li>响应头中的Access-Control-Allow-Origin一定不能为*，必须是指定的域名</li>
</ul>
<h4 id="特殊请求"><a href="#特殊请求" class="headerlink" title="特殊请求"></a>特殊请求</h4><p>不符合简单请求的条件，会被浏览器判定为特殊请求,，例如请求方式为PUT。</p>
<blockquote>
<p>预检请求</p>
</blockquote>
<p>特殊请求会在正式通信之前，增加一次HTTP查询请求，称为”预检”请求（preflight）。</p>
<p>浏览器先询问服务器，当前网页所在的域名是否在服务器的许可名单之中，以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复，浏览器才会发出正式的<code>XMLHttpRequest</code>请求，否则就报错。</p>
<p>一个“预检”请求的样板：</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">OPTIONS</span> <span class="string">/cors</span> HTTP/1.1</span><br><span class="line"><span class="attribute">Origin</span>: http://manage.leyou.com</span><br><span class="line"><span class="attribute">Access-Control-Request-Method</span>: PUT</span><br><span class="line"><span class="attribute">Access-Control-Request-Headers</span>: X-Custom-Header</span><br><span class="line"><span class="attribute">Host</span>: api.leyou.com</span><br><span class="line"><span class="attribute">Accept-Language</span>: en-US</span><br><span class="line"><span class="attribute">Connection</span>: keep-alive</span><br><span class="line"><span class="attribute">User-Agent</span>: Mozilla/5.0...</span><br></pre></td></tr></table></figure>

<p>与简单请求相比，除了Origin以外，多了两个头：</p>
<ul>
<li>Access-Control-Request-Method：接下来会用到的请求方式，比如PUT</li>
<li>Access-Control-Request-Headers：会额外用到的头信息</li>
</ul>
<blockquote>
<p>预检请求的响应</p>
</blockquote>
<p>服务的收到预检请求，如果许可跨域，会发出响应：</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.1 <span class="number">200</span> OK</span><br><span class="line"><span class="attribute">Date</span>: Mon, 01 Dec 2008 01:15:39 GMT</span><br><span class="line"><span class="attribute">Server</span>: Apache/2.0.61 (Unix)</span><br><span class="line"><span class="attribute">Access-Control-Allow-Origin</span>: http://manage.leyou.com</span><br><span class="line"><span class="attribute">Access-Control-Allow-Credentials</span>: true</span><br><span class="line"><span class="attribute">Access-Control-Allow-Methods</span>: GET, POST, PUT</span><br><span class="line"><span class="attribute">Access-Control-Allow-Headers</span>: X-Custom-Header</span><br><span class="line"><span class="attribute">Access-Control-Max-Age</span>: 1728000</span><br><span class="line"><span class="attribute">Content-Type</span>: text/html; charset=utf-8</span><br><span class="line"><span class="attribute">Content-Encoding</span>: gzip</span><br><span class="line"><span class="attribute">Content-Length</span>: 0</span><br><span class="line"><span class="attribute">Keep-Alive</span>: timeout=2, max=100</span><br><span class="line"><span class="attribute">Connection</span>: Keep-Alive</span><br><span class="line"><span class="attribute">Content-Type</span>: text/plain</span><br></pre></td></tr></table></figure>

<p>除了<code>Access-Control-Allow-Origin</code>和<code>Access-Control-Allow-Credentials</code>以外，这里又额外多出3个头：</p>
<ul>
<li>Access-Control-Allow-Methods：允许访问的方式</li>
<li>Access-Control-Allow-Headers：允许携带的头</li>
<li>Access-Control-Max-Age：本次许可的有效时长，单位是秒，<strong>过期之前的ajax请求就无需再次进行预检了</strong></li>
</ul>
<p>如果浏览器得到上述响应，则认定为可以跨域，后续就跟简单请求的处理是一样的了。</p>
<h3 id="2-5-3-实现非常简单"><a href="#2-5-3-实现非常简单" class="headerlink" title="2.5.3.实现非常简单"></a>2.5.3.实现非常简单</h3><p>虽然原理比较复杂，但是前面说过：</p>
<ul>
<li>浏览器端都有浏览器自动完成，我们无需操心</li>
<li>服务端可以通过拦截器统一实现，不必每次都去进行跨域判定的编写。</li>
</ul>
<p>事实上，SpringMVC已经帮我们写好了CORS的跨域过滤器：CorsFilter ,内部已经实现了刚才所讲的判定逻辑，我们直接用就好了。</p>
<p>在<code>ly-api-gateway</code>中编写一个配置类，并且注册CorsFilter：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.cors.CorsConfiguration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.cors.UrlBasedCorsConfigurationSource;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.filter.CorsFilter;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GlobalCorsConfig</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> CorsFilter <span class="title">corsFilter</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//1.添加CORS配置信息</span></span><br><span class="line">        CorsConfiguration config = <span class="keyword">new</span> CorsConfiguration();</span><br><span class="line">        <span class="comment">//1) 允许的域,不要写*，否则cookie就无法使用了</span></span><br><span class="line">        config.addAllowedOrigin(<span class="string">&quot;http://manage.leyou.com&quot;</span>);</span><br><span class="line">        <span class="comment">//2) 是否发送Cookie信息</span></span><br><span class="line">        config.setAllowCredentials(<span class="keyword">true</span>);</span><br><span class="line">        <span class="comment">//3) 允许的请求方式</span></span><br><span class="line">        config.addAllowedMethod(<span class="string">&quot;OPTIONS&quot;</span>);</span><br><span class="line">        config.addAllowedMethod(<span class="string">&quot;HEAD&quot;</span>);</span><br><span class="line">        config.addAllowedMethod(<span class="string">&quot;GET&quot;</span>);</span><br><span class="line">        config.addAllowedMethod(<span class="string">&quot;PUT&quot;</span>);</span><br><span class="line">        config.addAllowedMethod(<span class="string">&quot;POST&quot;</span>);</span><br><span class="line">        config.addAllowedMethod(<span class="string">&quot;DELETE&quot;</span>);</span><br><span class="line">        config.addAllowedMethod(<span class="string">&quot;PATCH&quot;</span>);</span><br><span class="line">        <span class="comment">// 4）允许的头信息</span></span><br><span class="line">        config.addAllowedHeader(<span class="string">&quot;*&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//2.添加映射路径，我们拦截一切请求</span></span><br><span class="line">        UrlBasedCorsConfigurationSource configSource = <span class="keyword">new</span> UrlBasedCorsConfigurationSource();</span><br><span class="line">        configSource.registerCorsConfiguration(<span class="string">&quot;/**&quot;</span>, config);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//3.返回新的CorsFilter.</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> CorsFilter(configSource);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>结构：</p>
<p> <img src="assets/1526021505774.png" alt="1526021505774"></p>
<p>4.5.4.重启测试：</p>
<p>访问正常：</p>
<p> <img src="assets/1526021419016.png" alt="1526021419016"></p>
<p>页面也OK了：</p>
<p><img src="assets/1526021447335.png" alt="1526021447335"></p>
<p>分类的增删改功能暂时就不做了，页面已经预留好了事件接口，有兴趣的同学可以完成一下。</p>
<h1 id="3-品牌的查询"><a href="#3-品牌的查询" class="headerlink" title="3.品牌的查询"></a>3.品牌的查询</h1><p>商品分类完成以后，自然轮到了品牌功能了。</p>
<p>先看看我们要实现的效果：</p>
<p><img src="assets/1526021968036.png" alt="1526021968036"></p>
<p>接下来，我们从0开始，实现下从前端到后端的完整开发。</p>
<h2 id="3-1-从0开始"><a href="#3-1-从0开始" class="headerlink" title="3.1.从0开始"></a>3.1.从0开始</h2><p>为了方便看到效果，我们新建一个MyBrand.vue（注意先停掉服务器），从0开始搭建。</p>
<p> <img src="assets/1526023142926.png" alt="1526023142926"></p>
<p>内容初始化一下：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;span&gt;</span><br><span class="line">    hello</span><br><span class="line">  &lt;&#x2F;span&gt;</span><br><span class="line">&lt;&#x2F;template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">    export default &#123;</span><br><span class="line">        name: &quot;my-brand&quot;</span><br><span class="line">    &#125;</span><br><span class="line">&lt;&#x2F;script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style scoped&gt;</span><br><span class="line"></span><br><span class="line">&lt;&#x2F;style&gt;</span><br></pre></td></tr></table></figure>

<p>改变router新的index.js，将路由地址指向MyBrand.vue</p>
<p><img src="assets/1526023276997.png" alt="1526023276997"></p>
<p>打开服务器，再次查看页面：</p>
<p><img src="assets/1526023471428.png" alt="1526023471428"></p>
<p>干干净净了。</p>
<h2 id="3-2-品牌查询页面"><a href="#3-2-品牌查询页面" class="headerlink" title="3.2.品牌查询页面"></a>3.2.品牌查询页面</h2><h3 id="3-2-1-data-tables组件"><a href="#3-2-1-data-tables组件" class="headerlink" title="3.2.1.data-tables组件"></a>3.2.1.data-tables组件</h3><p>大家看到这个原型页面肯定能看出，其主体就是一个table。我们去Vuetify查看有关table的文档：</p>
<p><img src="assets/1526023540226.png" alt="1526023540226"></p>
<p>仔细阅读，发现<code>v-data-table</code>中有以下核心属性：</p>
<ul>
<li><p>dark：是否使用黑暗色彩主题，默认是false</p>
</li>
<li><p>expand：表格的行是否可以展开，默认是false</p>
</li>
<li><p>headers：定义表头的数组，数组的每个元素就是一个表头信息对象，结构：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  text: string, <span class="comment">// 表头的显示文本</span></span><br><span class="line">  value: string, <span class="comment">// 表头对应的每行数据的key</span></span><br><span class="line">  align: <span class="string">&#x27;left&#x27;</span> | <span class="string">&#x27;center&#x27;</span> | <span class="string">&#x27;right&#x27;</span>, <span class="comment">// 位置</span></span><br><span class="line">  sortable: boolean, <span class="comment">// 是否可排序</span></span><br><span class="line">  class: string[] | string,// 样式</span><br><span class="line">  width: string,<span class="comment">// 宽度</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>items：表格的数据的数组，数组的每个元素是一行数据的对象，对象的key要与表头的value一致</p>
</li>
<li><p>loading：是否显示加载数据的进度条，默认是false</p>
</li>
<li><p>no-data-text：当没有查询到数据时显示的提示信息，string类型，无默认值</p>
</li>
<li><p>pagination.sync：包含分页和排序信息的对象，将其与vue实例中的属性关联，表格的分页或排序按钮被触发时，会自动将最新的分页和排序信息更新。对象结构：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    page: <span class="number">1</span>, <span class="comment">// 当前页</span></span><br><span class="line">    rowsPerPage: <span class="number">5</span>, <span class="comment">// 每页大小</span></span><br><span class="line">    sortBy: <span class="string">&#x27;&#x27;</span>, <span class="comment">// 排序字段</span></span><br><span class="line">    descending:<span class="literal">false</span>, <span class="comment">// 是否降序</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>total-items：分页的总条数信息，number类型，无默认值</p>
</li>
<li><p>select-all ：是否显示每一行的复选框，Boolean类型，无默认值</p>
</li>
<li><p>value：当表格可选的时候，返回选中的行</p>
</li>
</ul>
<p>我们向下翻，找找有没有看起来牛逼的案例。</p>
<p>找到这样一条：</p>
<p><img src="assets/1526023837773.png" alt="1526023837773"></p>
<p>其它的案例都是由Vuetify帮我们对查询到的当前页数据进行排序和分页，这显然不是我们想要的。我们希望能在服务端完成对整体品牌数据的排序和分页，而这个案例恰好合适。</p>
<p>点击按钮，我们直接查看源码，然后直接复制到MyBrand.vue中</p>
<p>模板：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;v-data-table</span><br><span class="line">      :headers&#x3D;&quot;headers&quot;</span><br><span class="line">      :items&#x3D;&quot;desserts&quot;</span><br><span class="line">      :search&#x3D;&quot;search&quot;</span><br><span class="line">      :pagination.sync&#x3D;&quot;pagination&quot;</span><br><span class="line">      :total-items&#x3D;&quot;totalDesserts&quot;</span><br><span class="line">      :loading&#x3D;&quot;loading&quot;</span><br><span class="line">      class&#x3D;&quot;elevation-1&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      &lt;template slot&#x3D;&quot;items&quot; slot-scope&#x3D;&quot;props&quot;&gt;</span><br><span class="line">        &lt;td&gt;&#123;&#123; props.item.name &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-right&quot;&gt;&#123;&#123; props.item.calories &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-right&quot;&gt;&#123;&#123; props.item.fat &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-right&quot;&gt;&#123;&#123; props.item.carbs &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-right&quot;&gt;&#123;&#123; props.item.protein &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-right&quot;&gt;&#123;&#123; props.item.iron &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">      &lt;&#x2F;template&gt;</span><br><span class="line">    &lt;&#x2F;v-data-table&gt;</span><br><span class="line">  &lt;&#x2F;div&gt;</span><br><span class="line">&lt;&#x2F;template&gt;</span><br></pre></td></tr></table></figure>



<h3 id="3-2-2-分析"><a href="#3-2-2-分析" class="headerlink" title="3.2.2.分析"></a>3.2.2.分析</h3><p>接下来，就分析一下案例中每一部分是什么意思，搞清楚了，我们也可以自己玩了。</p>
<p>先看模板中table上的一些属性：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;v-data-table</span><br><span class="line">              :headers&#x3D;&quot;headers&quot;</span><br><span class="line">              :items&#x3D;&quot;desserts&quot;</span><br><span class="line">              :search&#x3D;&quot;search&quot;</span><br><span class="line">              :pagination.sync&#x3D;&quot;pagination&quot;</span><br><span class="line">              :total-items&#x3D;&quot;totalDesserts&quot;</span><br><span class="line">              :loading&#x3D;&quot;loading&quot;</span><br><span class="line">              class&#x3D;&quot;elevation-1&quot;</span><br><span class="line">              &gt;</span><br><span class="line">&lt;&#x2F;v-data-table&gt;</span><br></pre></td></tr></table></figure>

<ul>
<li><p>headers：表头信息，是一个数组</p>
</li>
<li><p>items：要在表格中展示的数据，数组结构，每一个元素是一行</p>
</li>
<li><p>search：搜索过滤字段，用不到，暂时不管</p>
</li>
<li><p>pagination.sync：分页信息，包含了当前页，每页大小，排序字段，排序方式等。加上.sync代表服务端排序，当用户点击分页条时，该对象的值会跟着变化。监控这个值，并在这个值变化时去服务端查询，即可实现页面数据动态加载了。</p>
</li>
<li><p>total-items：总条数</p>
</li>
<li><p>loading：boolean类型，true：代表数据正在加载，会有进度条。false：数据加载完毕。</p>
<p><img src="assets/1526029254159.png" alt="1526029254159"></p>
</li>
</ul>
<p>另外，在<code>v-data-tables</code>中，我们还看到另一段代码：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&lt;template slot&#x3D;&quot;items&quot; slot-scope&#x3D;&quot;props&quot;&gt;</span><br><span class="line">        &lt;td&gt;&#123;&#123; props.item.name &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-right&quot;&gt;&#123;&#123; props.item.calories &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-right&quot;&gt;&#123;&#123; props.item.fat &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-right&quot;&gt;&#123;&#123; props.item.carbs &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-right&quot;&gt;&#123;&#123; props.item.protein &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-right&quot;&gt;&#123;&#123; props.item.iron &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">&lt;&#x2F;template&gt;</span><br></pre></td></tr></table></figure>

<p>这段就是在渲染每一行的数据。Vue会自动遍历上面传递的<code>items</code>属性，并把得到的对象传递给这段<code>template</code>中的<code>props.item</code>属性。我们从中得到数据，渲染在页面即可。</p>
<p>我们需要做的事情，主要有两件：</p>
<ul>
<li>给items和totalItems赋值</li>
<li>当pagination变化时，重新获取数据，再次给items和totalItems赋值</li>
</ul>
<h3 id="3-2-3-初步实现"><a href="#3-2-3-初步实现" class="headerlink" title="3.2.3.初步实现"></a>3.2.3.初步实现</h3><p>我们先弄点假品牌数据：</p>
<figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">&quot;id&quot;</span>: <span class="number">2032</span>,</span><br><span class="line">    <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;OPPO&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;image&quot;</span>: <span class="string">&quot;http://img10.360buyimg.com/popshop/jfs/t2119/133/2264148064/4303/b8ab3755/56b2f385N8e4eb051.jpg&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;letter&quot;</span>: <span class="string">&quot;O&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">&quot;id&quot;</span>: <span class="number">2033</span>,</span><br><span class="line">    <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;飞利浦（PHILIPS）&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;image&quot;</span>: <span class="string">&quot;http://img12.360buyimg.com/popshop/jfs/t18361/122/1318410299/1870/36fe70c9/5ac43a4dNa44a0ce0.jpg&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;letter&quot;</span>: <span class="string">&quot;F&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">&quot;id&quot;</span>: <span class="number">2034</span>,</span><br><span class="line">    <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;华为（HUAWEI）&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;image&quot;</span>: <span class="string">&quot;http://img10.360buyimg.com/popshop/jfs/t5662/36/8888655583/7806/1c629c01/598033b4Nd6055897.jpg&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;letter&quot;</span>: <span class="string">&quot;H&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">&quot;id&quot;</span>: <span class="number">2036</span>,</span><br><span class="line">    <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;酷派（Coolpad）&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;image&quot;</span>: <span class="string">&quot;http://img10.360buyimg.com/popshop/jfs/t2521/347/883897149/3732/91c917ec/5670cf96Ncffa2ae6.jpg&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;letter&quot;</span>: <span class="string">&quot;K&quot;</span></span><br><span class="line">  &#125;,</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">&quot;id&quot;</span>: <span class="number">2037</span>,</span><br><span class="line">    <span class="attr">&quot;name&quot;</span>: <span class="string">&quot;魅族（MEIZU）&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;image&quot;</span>: <span class="string">&quot;http://img13.360buyimg.com/popshop/jfs/t3511/131/31887105/4943/48f83fa9/57fdf4b8N6e95624d.jpg&quot;</span>,</span><br><span class="line">    <span class="attr">&quot;letter&quot;</span>: <span class="string">&quot;M&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<p>品牌中有id,name,image,letter字段。</p>
<h4 id="修改模板"><a href="#修改模板" class="headerlink" title="修改模板"></a>修改模板</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&lt;div&gt;</span><br><span class="line">  &lt;v-data-table</span><br><span class="line">    :headers&#x3D;&quot;headers&quot;</span><br><span class="line">    :items&#x3D;&quot;brands&quot;</span><br><span class="line">    :search&#x3D;&quot;search&quot;</span><br><span class="line">    :pagination.sync&#x3D;&quot;pagination&quot;</span><br><span class="line">    :total-items&#x3D;&quot;totalBrands&quot;</span><br><span class="line">    :loading&#x3D;&quot;loading&quot;</span><br><span class="line">    class&#x3D;&quot;elevation-1&quot;</span><br><span class="line">  &gt;</span><br><span class="line">    &lt;template slot&#x3D;&quot;items&quot; slot-scope&#x3D;&quot;props&quot;&gt;</span><br><span class="line">      &lt;td&gt;&#123;&#123; props.item.id &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">      &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.name &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">      &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;</span><br><span class="line">        &lt;img v-if&#x3D;&quot;props.item.image&quot; :src&#x3D;&quot;props.item.image&quot; width&#x3D;&quot;130&quot; height&#x3D;&quot;40&quot;&gt;</span><br><span class="line">        &lt;span v-else&gt;无&lt;&#x2F;span&gt;</span><br><span class="line">      &lt;&#x2F;td&gt;</span><br><span class="line">      &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.letter &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">    &lt;&#x2F;template&gt;</span><br><span class="line">  &lt;&#x2F;v-data-table&gt;</span><br><span class="line">&lt;&#x2F;div&gt;</span><br></pre></td></tr></table></figure>

<p>我们修改了以下部分：</p>
<ul>
<li>items：指向一个brands变量，等下在js代码中定义</li>
<li>total-items：指向了totalBrands变量，等下在js代码中定义</li>
<li>template模板中，渲染了四个字段：<ul>
<li>id：</li>
<li>name</li>
<li>image，注意，我们不是以文本渲染，而是赋值到一个<code>img</code>标签的src属性中，并且做了非空判断</li>
<li>letter</li>
</ul>
</li>
</ul>
<h4 id="编写数据"><a href="#编写数据" class="headerlink" title="编写数据"></a>编写数据</h4><p>接下来编写要用到的数据：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">    data() &#123;</span><br><span class="line">      <span class="keyword">return</span> &#123;</span><br><span class="line">        search: <span class="string">&#x27;&#x27;</span>, <span class="comment">// 搜索过滤字段</span></span><br><span class="line">        totalBrands: <span class="number">0</span>, <span class="comment">// 总条数</span></span><br><span class="line">        brands: [], <span class="comment">// 当前页品牌数据</span></span><br><span class="line">        loading: <span class="literal">true</span>, <span class="comment">// 是否在加载中</span></span><br><span class="line">        pagination: &#123;&#125;, <span class="comment">// 分页信息</span></span><br><span class="line">        headers: [ <span class="comment">// 头信息</span></span><br><span class="line">          &#123;<span class="attr">text</span>: <span class="string">&#x27;id&#x27;</span>, <span class="attr">align</span>: <span class="string">&#x27;center&#x27;</span>, <span class="attr">value</span>: <span class="string">&#x27;id&#x27;</span>&#125;,</span><br><span class="line">          &#123;<span class="attr">text</span>: <span class="string">&#x27;名称&#x27;</span>, <span class="attr">align</span>: <span class="string">&#x27;center&#x27;</span>, <span class="attr">sortable</span>: <span class="literal">false</span>, <span class="attr">value</span>: <span class="string">&#x27;name&#x27;</span>&#125;,</span><br><span class="line">          &#123;<span class="attr">text</span>: <span class="string">&#x27;LOGO&#x27;</span>, <span class="attr">align</span>: <span class="string">&#x27;center&#x27;</span>, <span class="attr">sortable</span>: <span class="literal">false</span>, <span class="attr">value</span>: <span class="string">&#x27;image&#x27;</span>&#125;,</span><br><span class="line">          &#123;<span class="attr">text</span>: <span class="string">&#x27;首字母&#x27;</span>, <span class="attr">align</span>: <span class="string">&#x27;center&#x27;</span>, <span class="attr">value</span>: <span class="string">&#x27;letter&#x27;</span>, <span class="attr">sortable</span>: <span class="literal">true</span>,&#125;</span><br><span class="line">        ]</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="编写函数，初始化数据"><a href="#编写函数，初始化数据" class="headerlink" title="编写函数，初始化数据"></a>编写函数，初始化数据</h4><p>接下来就是对brands和totalBrands完成赋值动作了。</p>
<p>我们编写一个函数来完成赋值，提高复用性：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line">methods:&#123;</span><br><span class="line">      getDataFromServer()&#123; <span class="comment">// 从服务的加载数据的方法。</span></span><br><span class="line">        <span class="comment">// 伪造假数据</span></span><br><span class="line">        <span class="keyword">const</span> brands = [</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="string">&quot;id&quot;</span>: <span class="number">2032</span>,</span><br><span class="line">            <span class="string">&quot;name&quot;</span>: <span class="string">&quot;OPPO&quot;</span>,</span><br><span class="line">            <span class="string">&quot;image&quot;</span>: <span class="string">&quot;http://img10.360buyimg.com/popshop/jfs/t2119/133/2264148064/4303/b8ab3755/56b2f385N8e4eb051.jpg&quot;</span>,</span><br><span class="line">            <span class="string">&quot;letter&quot;</span>: <span class="string">&quot;O&quot;</span>,</span><br><span class="line">            <span class="string">&quot;categories&quot;</span>: <span class="literal">null</span></span><br><span class="line">          &#125;,</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="string">&quot;id&quot;</span>: <span class="number">2033</span>,</span><br><span class="line">            <span class="string">&quot;name&quot;</span>: <span class="string">&quot;飞利浦（PHILIPS）&quot;</span>,</span><br><span class="line">            <span class="string">&quot;image&quot;</span>: <span class="string">&quot;http://img12.360buyimg.com/popshop/jfs/t18361/122/1318410299/1870/36fe70c9/5ac43a4dNa44a0ce0.jpg&quot;</span>,</span><br><span class="line">            <span class="string">&quot;letter&quot;</span>: <span class="string">&quot;F&quot;</span>,</span><br><span class="line">            <span class="string">&quot;categories&quot;</span>: <span class="literal">null</span></span><br><span class="line">          &#125;,</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="string">&quot;id&quot;</span>: <span class="number">2034</span>,</span><br><span class="line">            <span class="string">&quot;name&quot;</span>: <span class="string">&quot;华为（HUAWEI）&quot;</span>,</span><br><span class="line">            <span class="string">&quot;image&quot;</span>: <span class="string">&quot;http://img10.360buyimg.com/popshop/jfs/t5662/36/8888655583/7806/1c629c01/598033b4Nd6055897.jpg&quot;</span>,</span><br><span class="line">            <span class="string">&quot;letter&quot;</span>: <span class="string">&quot;H&quot;</span>,</span><br><span class="line">            <span class="string">&quot;categories&quot;</span>: <span class="literal">null</span></span><br><span class="line">          &#125;,</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="string">&quot;id&quot;</span>: <span class="number">2036</span>,</span><br><span class="line">            <span class="string">&quot;name&quot;</span>: <span class="string">&quot;酷派（Coolpad）&quot;</span>,</span><br><span class="line">            <span class="string">&quot;image&quot;</span>: <span class="string">&quot;http://img10.360buyimg.com/popshop/jfs/t2521/347/883897149/3732/91c917ec/5670cf96Ncffa2ae6.jpg&quot;</span>,</span><br><span class="line">            <span class="string">&quot;letter&quot;</span>: <span class="string">&quot;K&quot;</span>,</span><br><span class="line">            <span class="string">&quot;categories&quot;</span>: <span class="literal">null</span></span><br><span class="line">          &#125;,</span><br><span class="line">          &#123;</span><br><span class="line">            <span class="string">&quot;id&quot;</span>: <span class="number">2037</span>,</span><br><span class="line">            <span class="string">&quot;name&quot;</span>: <span class="string">&quot;魅族（MEIZU）&quot;</span>,</span><br><span class="line">            <span class="string">&quot;image&quot;</span>: <span class="string">&quot;http://img13.360buyimg.com/popshop/jfs/t3511/131/31887105/4943/48f83fa9/57fdf4b8N6e95624d.jpg&quot;</span>,</span><br><span class="line">            <span class="string">&quot;letter&quot;</span>: <span class="string">&quot;M&quot;</span>,</span><br><span class="line">            <span class="string">&quot;categories&quot;</span>: <span class="literal">null</span></span><br><span class="line">          &#125;</span><br><span class="line">        ];</span><br><span class="line">        <span class="comment">// 模拟延迟一段时间，随后进行赋值</span></span><br><span class="line">        <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">          <span class="comment">// 然后赋值给brands</span></span><br><span class="line">          <span class="built_in">this</span>.brands = brands;</span><br><span class="line">          <span class="built_in">this</span>.totalBrands = brands.length;</span><br><span class="line">          <span class="comment">// 完成赋值后，把加载状态赋值为false</span></span><br><span class="line">          <span class="built_in">this</span>.loading = <span class="literal">false</span>;</span><br><span class="line">        &#125;,<span class="number">400</span>)</span><br><span class="line">      &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>然后使用钩子函数，在Vue实例初始化完毕后调用这个方法，这里使用mounted（渲染后）函数：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mounted()&#123; <span class="comment">// 渲染后执行</span></span><br><span class="line">    <span class="comment">// 查询数据</span></span><br><span class="line">    <span class="built_in">this</span>.getDataFromServer();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;v-data-table</span><br><span class="line">      :headers&#x3D;&quot;headers&quot;</span><br><span class="line">      :items&#x3D;&quot;brands&quot;</span><br><span class="line">      :search&#x3D;&quot;search&quot;</span><br><span class="line">      :pagination.sync&#x3D;&quot;pagination&quot;</span><br><span class="line">      :total-items&#x3D;&quot;totalBrands&quot;</span><br><span class="line">      :loading&#x3D;&quot;loading&quot;</span><br><span class="line">      class&#x3D;&quot;elevation-1&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      &lt;template slot&#x3D;&quot;items&quot; slot-scope&#x3D;&quot;props&quot;&gt;</span><br><span class="line">        &lt;td&gt;&#123;&#123; props.item.id &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.name &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&lt;img :src&#x3D;&quot;props.item.image&quot;&gt;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.letter &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">      &lt;&#x2F;template&gt;</span><br><span class="line">    &lt;&#x2F;v-data-table&gt;</span><br><span class="line">  &lt;&#x2F;div&gt;</span><br><span class="line">&lt;&#x2F;template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">  export default &#123;</span><br><span class="line">    name: &quot;my-brand&quot;,</span><br><span class="line">    data() &#123;</span><br><span class="line">      return &#123;</span><br><span class="line">        search: &#39;&#39;, &#x2F;&#x2F; 搜索过滤字段</span><br><span class="line">        totalBrands: 0, &#x2F;&#x2F; 总条数</span><br><span class="line">        brands: [], &#x2F;&#x2F; 当前页品牌数据</span><br><span class="line">        loading: true, &#x2F;&#x2F; 是否在加载中</span><br><span class="line">        pagination: &#123;&#125;, &#x2F;&#x2F; 分页信息</span><br><span class="line">        headers: [</span><br><span class="line">          &#123;text: &#39;id&#39;, align: &#39;center&#39;, value: &#39;id&#39;&#125;,</span><br><span class="line">          &#123;text: &#39;名称&#39;, align: &#39;center&#39;, sortable: false, value: &#39;name&#39;&#125;,</span><br><span class="line">          &#123;text: &#39;LOGO&#39;, align: &#39;center&#39;, sortable: false, value: &#39;image&#39;&#125;,</span><br><span class="line">          &#123;text: &#39;首字母&#39;, align: &#39;center&#39;, value: &#39;letter&#39;, sortable: true,&#125;</span><br><span class="line">        ]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    mounted()&#123; &#x2F;&#x2F; 渲染后执行</span><br><span class="line">      &#x2F;&#x2F; 查询数据</span><br><span class="line">      this.getDataFromServer();</span><br><span class="line">    &#125;,</span><br><span class="line">    methods:&#123;</span><br><span class="line">      getDataFromServer()&#123; &#x2F;&#x2F; 从服务的加载数的方法。</span><br><span class="line">        &#x2F;&#x2F; 伪造假数据</span><br><span class="line">        const brands &#x3D; [</span><br><span class="line">          &#123;</span><br><span class="line">            &quot;id&quot;: 2032,</span><br><span class="line">            &quot;name&quot;: &quot;OPPO&quot;,</span><br><span class="line">            &quot;image&quot;: &quot;http:&#x2F;&#x2F;img10.360buyimg.com&#x2F;popshop&#x2F;jfs&#x2F;t2119&#x2F;133&#x2F;2264148064&#x2F;4303&#x2F;b8ab3755&#x2F;56b2f385N8e4eb051.jpg&quot;,</span><br><span class="line">            &quot;letter&quot;: &quot;O&quot;,</span><br><span class="line">            &quot;categories&quot;: null</span><br><span class="line">          &#125;,</span><br><span class="line">          &#123;</span><br><span class="line">            &quot;id&quot;: 2033,</span><br><span class="line">            &quot;name&quot;: &quot;飞利浦（PHILIPS）&quot;,</span><br><span class="line">            &quot;image&quot;: &quot;http:&#x2F;&#x2F;img12.360buyimg.com&#x2F;popshop&#x2F;jfs&#x2F;t18361&#x2F;122&#x2F;1318410299&#x2F;1870&#x2F;36fe70c9&#x2F;5ac43a4dNa44a0ce0.jpg&quot;,</span><br><span class="line">            &quot;letter&quot;: &quot;F&quot;,</span><br><span class="line">            &quot;categories&quot;: null</span><br><span class="line">          &#125;,</span><br><span class="line">          &#123;</span><br><span class="line">            &quot;id&quot;: 2034,</span><br><span class="line">            &quot;name&quot;: &quot;华为（HUAWEI）&quot;,</span><br><span class="line">            &quot;image&quot;: &quot;http:&#x2F;&#x2F;img10.360buyimg.com&#x2F;popshop&#x2F;jfs&#x2F;t5662&#x2F;36&#x2F;8888655583&#x2F;7806&#x2F;1c629c01&#x2F;598033b4Nd6055897.jpg&quot;,</span><br><span class="line">            &quot;letter&quot;: &quot;H&quot;,</span><br><span class="line">            &quot;categories&quot;: null</span><br><span class="line">          &#125;,</span><br><span class="line">          &#123;</span><br><span class="line">            &quot;id&quot;: 2036,</span><br><span class="line">            &quot;name&quot;: &quot;酷派（Coolpad）&quot;,</span><br><span class="line">            &quot;image&quot;: &quot;http:&#x2F;&#x2F;img10.360buyimg.com&#x2F;popshop&#x2F;jfs&#x2F;t2521&#x2F;347&#x2F;883897149&#x2F;3732&#x2F;91c917ec&#x2F;5670cf96Ncffa2ae6.jpg&quot;,</span><br><span class="line">            &quot;letter&quot;: &quot;K&quot;,</span><br><span class="line">            &quot;categories&quot;: null</span><br><span class="line">          &#125;,</span><br><span class="line">          &#123;</span><br><span class="line">            &quot;id&quot;: 2037,</span><br><span class="line">            &quot;name&quot;: &quot;魅族（MEIZU）&quot;,</span><br><span class="line">            &quot;image&quot;: &quot;http:&#x2F;&#x2F;img13.360buyimg.com&#x2F;popshop&#x2F;jfs&#x2F;t3511&#x2F;131&#x2F;31887105&#x2F;4943&#x2F;48f83fa9&#x2F;57fdf4b8N6e95624d.jpg&quot;,</span><br><span class="line">            &quot;letter&quot;: &quot;M&quot;,</span><br><span class="line">            &quot;categories&quot;: null</span><br><span class="line">          &#125;</span><br><span class="line">        ];</span><br><span class="line">        &#x2F;&#x2F; 模拟延迟一段时间，随后进行赋值</span><br><span class="line">        setTimeout(() &#x3D;&gt; &#123;</span><br><span class="line">          &#x2F;&#x2F; 然后赋值给brands</span><br><span class="line">          this.brands &#x3D; brands;</span><br><span class="line">          this.totalBrands &#x3D; brands.length;</span><br><span class="line">          &#x2F;&#x2F; 完成赋值后，把加载状态赋值为false</span><br><span class="line">          this.loading &#x3D; false;</span><br><span class="line">        &#125;,400)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;&#x2F;script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style scoped&gt;</span><br><span class="line"></span><br><span class="line">&lt;&#x2F;style&gt;</span><br></pre></td></tr></table></figure>



<p>刷新页面查看：</p>
<p><img src="assets/1526029445561.png" alt="1526029445561"></p>
<h3 id="3-2-4-优化页面"><a href="#3-2-4-优化页面" class="headerlink" title="3.2.4.优化页面"></a>3.2.4.优化页面</h3><h4 id="编辑和删除按钮"><a href="#编辑和删除按钮" class="headerlink" title="编辑和删除按钮"></a>编辑和删除按钮</h4><p>我们将来要对品牌进行增删改，需要给每一行数据添加 修改删除的按钮，一般放到改行的最后一列：</p>
<p><img src="assets/1526029907794.png" alt="1526029907794"></p>
<p>其实就是多了一列，只是这一列没有数据，而是两个按钮而已。</p>
<p>我们先在头（headers）中添加一列：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">headers: [</span><br><span class="line">    &#123;<span class="attr">text</span>: <span class="string">&#x27;id&#x27;</span>, <span class="attr">align</span>: <span class="string">&#x27;center&#x27;</span>, <span class="attr">value</span>: <span class="string">&#x27;id&#x27;</span>&#125;,</span><br><span class="line">    &#123;<span class="attr">text</span>: <span class="string">&#x27;名称&#x27;</span>, <span class="attr">align</span>: <span class="string">&#x27;center&#x27;</span>, <span class="attr">sortable</span>: <span class="literal">false</span>, <span class="attr">value</span>: <span class="string">&#x27;name&#x27;</span>&#125;,</span><br><span class="line">    &#123;<span class="attr">text</span>: <span class="string">&#x27;LOGO&#x27;</span>, <span class="attr">align</span>: <span class="string">&#x27;center&#x27;</span>, <span class="attr">sortable</span>: <span class="literal">false</span>, <span class="attr">value</span>: <span class="string">&#x27;image&#x27;</span>&#125;,</span><br><span class="line">    &#123;<span class="attr">text</span>: <span class="string">&#x27;首字母&#x27;</span>, <span class="attr">align</span>: <span class="string">&#x27;center&#x27;</span>, <span class="attr">value</span>: <span class="string">&#x27;letter&#x27;</span>, <span class="attr">sortable</span>: <span class="literal">true</span>,&#125;,</span><br><span class="line">    &#123;<span class="attr">text</span>: <span class="string">&#x27;操作&#x27;</span>, <span class="attr">align</span>: <span class="string">&#x27;center&#x27;</span>, <span class="attr">value</span>: <span class="string">&#x27;id&#x27;</span>, <span class="attr">sortable</span>: <span class="literal">false</span>&#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<p>然后在模板中添加按钮：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">&lt;template slot&#x3D;&quot;items&quot; slot-scope&#x3D;&quot;props&quot;&gt;</span><br><span class="line">  &lt;td&gt;&#123;&#123; props.item.id &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">  &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.name &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">  &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&lt;img :src&#x3D;&quot;props.item.image&quot;&gt;&lt;&#x2F;td&gt;</span><br><span class="line">  &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.letter &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">  &lt;td class&#x3D;&quot;justify-center&quot;&gt;</span><br><span class="line">    编辑&#x2F;删除</span><br><span class="line">  &lt;&#x2F;td&gt;</span><br><span class="line">&lt;&#x2F;template&gt;</span><br></pre></td></tr></table></figure>

<p>因为不知道按钮怎么写，先放个普通文本看看：</p>
<p><img src="assets/1526030236992.png" alt="1526030236992"></p>
<p>然后在官方文档中找到按钮的用法：</p>
<p><img src="assets/1526030329303.png" alt="1526030329303"></p>
<p>修改我们的模板：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;template slot&#x3D;&quot;items&quot; slot-scope&#x3D;&quot;props&quot;&gt;</span><br><span class="line">    &lt;td&gt;&#123;&#123; props.item.id &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">    &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.name &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">    &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&lt;img :src&#x3D;&quot;props.item.image&quot;&gt;&lt;&#x2F;td&gt;</span><br><span class="line">    &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.letter &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">    &lt;td class&#x3D;&quot;justify-center layout&quot;&gt;</span><br><span class="line">        &lt;v-btn color&#x3D;&quot;info&quot;&gt;编辑&lt;&#x2F;v-btn&gt;</span><br><span class="line">        &lt;v-btn color&#x3D;&quot;warning&quot;&gt;删除&lt;&#x2F;v-btn&gt;</span><br><span class="line">    &lt;&#x2F;td&gt;</span><br><span class="line">&lt;&#x2F;template&gt;</span><br></pre></td></tr></table></figure>

<p><img src="assets/1526030431704.png" alt="1526030431704"></p>
<h4 id="新增按钮"><a href="#新增按钮" class="headerlink" title="新增按钮"></a>新增按钮</h4><p>因为新增根某个品牌无关，是独立的，因此我们可以放到表格的外面：</p>
<p> <img src="assets/1526030663178.png" alt="1526030663178"></p>
<p>效果：</p>
<p><img src="assets/1526030540341.png" alt="1526030540341"></p>
<h4 id="卡片（card）"><a href="#卡片（card）" class="headerlink" title="卡片（card）"></a>卡片（card）</h4><p>为了不让按钮显得过于孤立，我们可以将按<code>新增按钮</code>和<code>表格</code>放到一张卡片（card）中。</p>
<p>我们去官网查看卡片的用法：</p>
<p><img src="assets/1526031159242.png" alt="1526031159242"></p>
<p>卡片<code>v-card</code>包含四个基本组件：</p>
<ul>
<li>v-card-media：一般放图片或视频</li>
<li>v-card-title：卡片的标题，一般位于卡片顶部</li>
<li>v-card-text：卡片的文本（主体内容），一般位于卡片正中</li>
<li>v-card-action：卡片的按钮，一般位于卡片底部</li>
</ul>
<p>我们可以把<code>新增的按钮</code>放到<code>v-card-title</code>位置，把<code>table</code>放到下面，这样就成一个上下关系。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">&lt;v-card&gt;</span><br><span class="line">  &lt;!-- 卡片的头部 --&gt;</span><br><span class="line">  &lt;v-card-title&gt;</span><br><span class="line">    &lt;v-btn color&#x3D;&quot;primary&quot;&gt;新增&lt;&#x2F;v-btn&gt;</span><br><span class="line">  &lt;&#x2F;v-card-title&gt;</span><br><span class="line">  &lt;!-- 分割线 --&gt;</span><br><span class="line">  &lt;v-divider&#x2F;&gt;</span><br><span class="line">  &lt;!--卡片的中部--&gt;</span><br><span class="line">  &lt;v-data-table</span><br><span class="line">    :headers&#x3D;&quot;headers&quot;</span><br><span class="line">    :items&#x3D;&quot;brands&quot;</span><br><span class="line">    :search&#x3D;&quot;search&quot;</span><br><span class="line">    :pagination.sync&#x3D;&quot;pagination&quot;</span><br><span class="line">    :total-items&#x3D;&quot;totalBrands&quot;</span><br><span class="line">    :loading&#x3D;&quot;loading&quot;</span><br><span class="line">    class&#x3D;&quot;elevation-1&quot;</span><br><span class="line">  &gt;</span><br><span class="line">    &lt;template slot&#x3D;&quot;items&quot; slot-scope&#x3D;&quot;props&quot;&gt;</span><br><span class="line">      &lt;td&gt;&#123;&#123; props.item.id &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">      &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.name &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">      &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&lt;img :src&#x3D;&quot;props.item.image&quot;&gt;&lt;&#x2F;td&gt;</span><br><span class="line">      &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.letter &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">      &lt;td class&#x3D;&quot;justify-center layout&quot;&gt;</span><br><span class="line">        &lt;v-btn color&#x3D;&quot;info&quot;&gt;编辑&lt;&#x2F;v-btn&gt;</span><br><span class="line">        &lt;v-btn color&#x3D;&quot;warning&quot;&gt;删除&lt;&#x2F;v-btn&gt;</span><br><span class="line">      &lt;&#x2F;td&gt;</span><br><span class="line">    &lt;&#x2F;template&gt;</span><br><span class="line">  &lt;&#x2F;v-data-table&gt;</span><br><span class="line">&lt;&#x2F;v-card&gt;</span><br></pre></td></tr></table></figure>

<p>效果：</p>
<p><img src="assets/1526031720583.png" alt="1526031720583"></p>
<h4 id="添加搜索框"><a href="#添加搜索框" class="headerlink" title="添加搜索框"></a>添加搜索框</h4><p>我们还可以在卡片头部添加一个搜索框，其实就是一个文本输入框。</p>
<p>查看官网中，文本框的用法：</p>
<p><img src="assets/1526031897445.png" alt="1526031897445"></p>
<ul>
<li>name：字段名，表单中会用到</li>
<li>label：提示文字</li>
<li>value：值。可以用v-model代替，实现双向绑定</li>
</ul>
<p>修改模板，添加输入框：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">v-card-title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">v-btn</span> <span class="attr">color</span>=<span class="string">&quot;primary&quot;</span>&gt;</span>新增品牌<span class="tag">&lt;/<span class="name">v-btn</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--搜索框，与search属性关联--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">v-text-field</span> <span class="attr">label</span>=<span class="string">&quot;输入关键字搜索&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;search&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">v-card-title</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>效果：</p>
<p><img src="assets/1526032177687.png" alt="1526032177687"></p>
<p>发现输入框变的超级长！！！</p>
<p>这个时候，我们可以使用Vuetify提供的一个空间隔离工具：</p>
<p><img src="assets/1526032321057.png" alt="1526032321057"></p>
<p>修改代码：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">v-card-title</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">v-btn</span> <span class="attr">color</span>=<span class="string">&quot;primary&quot;</span>&gt;</span>新增品牌<span class="tag">&lt;/<span class="name">v-btn</span>&gt;</span></span><br><span class="line">  <span class="comment">&lt;!--空间隔离组件--&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">v-spacer</span> /&gt;</span></span><br><span class="line">  <span class="comment">&lt;!--搜索框，与search属性关联--&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">v-text-field</span> <span class="attr">label</span>=<span class="string">&quot;输入关键字搜索&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;search&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">v-card-title</span>&gt;</span></span><br></pre></td></tr></table></figure>



<p><img src="assets/1526032398630.png" alt="1526032398630"></p>
<h4 id="给搜索框添加搜索图标"><a href="#给搜索框添加搜索图标" class="headerlink" title="给搜索框添加搜索图标"></a>给搜索框添加搜索图标</h4><p>查看textfiled的文档，发现：</p>
<p> <img src="assets/1526033007616.png" alt="1526033007616"></p>
<p>通过append-icon属性可以为 输入框添加后置图标，所有可用图标名称可以到 <a target="_blank" rel="noopener" href="https://material.io/tools/icons/">material-icons官网</a>去查看。</p>
<p>修改我们的代码：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">v-text-field</span> <span class="attr">label</span>=<span class="string">&quot;输入关键字搜索&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;search&quot;</span> <span class="attr">append-icon</span>=<span class="string">&quot;search&quot;</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<p><img src="assets/1526033167381.png" alt="1526033167381"></p>
<h4 id="把文本框变紧凑"><a href="#把文本框变紧凑" class="headerlink" title="把文本框变紧凑"></a>把文本框变紧凑</h4><p>搜索框看起来高度比较高，页面不够紧凑。这其实是因为默认在文本框下面预留有错误提示空间。通过下面的属性可以取消提示：</p>
<p><img src="assets/1526033439890.png" alt="1526033439890"></p>
<p>修改代码：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">v-text-field</span> <span class="attr">label</span>=<span class="string">&quot;输入关键字搜索&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;search&quot;</span> <span class="attr">append-icon</span>=<span class="string">&quot;search&quot;</span> <span class="attr">hide-details</span>/&gt;</span></span><br></pre></td></tr></table></figure>

<p>效果：</p>
<p><img src="assets/1526033500219.png" alt="1526033500219"></p>
<p>几乎已经达到了原来一样的效果了吧！</p>
<h2 id="3-3-后台提供查询接口"><a href="#3-3-后台提供查询接口" class="headerlink" title="3.3.后台提供查询接口"></a>3.3.后台提供查询接口</h2><p>前台页面已经准备好，接下来就是后台提供数据接口了。</p>
<h3 id="3-3-1-数据库表"><a href="#3-3-1-数据库表" class="headerlink" title="3.3.1.数据库表"></a>3.3.1.数据库表</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE &#96;tb_brand&#96; (</span><br><span class="line">  &#96;id&#96; bigint(20) NOT NULL AUTO_INCREMENT COMMENT &#39;品牌id&#39;,</span><br><span class="line">  &#96;name&#96; varchar(50) NOT NULL COMMENT &#39;品牌名称&#39;,</span><br><span class="line">  &#96;image&#96; varchar(200) DEFAULT &#39;&#39; COMMENT &#39;品牌图片地址&#39;,</span><br><span class="line">  &#96;letter&#96; char(1) DEFAULT &#39;&#39; COMMENT &#39;品牌的首字母&#39;,</span><br><span class="line">  PRIMARY KEY (&#96;id&#96;)</span><br><span class="line">) ENGINE&#x3D;InnoDB AUTO_INCREMENT&#x3D;325400 DEFAULT CHARSET&#x3D;utf8 COMMENT&#x3D;&#39;品牌表，一个品牌下有多个商品（spu），一对多关系&#39;;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>简单的四个字段，不多解释。</p>
<p>这里需要注意的是，品牌和商品分类之间是多对多关系。因此我们有一张中间表，来维护两者间关系：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE &#96;tb_category_brand&#96; (</span><br><span class="line">  &#96;category_id&#96; bigint(20) NOT NULL COMMENT &#39;商品类目id&#39;,</span><br><span class="line">  &#96;brand_id&#96; bigint(20) NOT NULL COMMENT &#39;品牌id&#39;,</span><br><span class="line">  PRIMARY KEY (&#96;category_id&#96;,&#96;brand_id&#96;)</span><br><span class="line">) ENGINE&#x3D;InnoDB DEFAULT CHARSET&#x3D;utf8 COMMENT&#x3D;&#39;商品分类和品牌的中间表，两者是多对多关系&#39;;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>但是，你可能会发现，这张表中并<strong>没有设置外键约束</strong>，似乎与数据库的设计范式不符。为什么这么做？</p>
<ul>
<li>外键会严重影响数据库读写的效率</li>
<li>数据删除时会比较麻烦</li>
</ul>
<p>在电商行业，性能是非常重要的。我们宁可在代码中通过逻辑来维护表关系，也不设置外键。</p>
<h3 id="3-3-2-实体类"><a href="#3-3-2-实体类" class="headerlink" title="3.3.2.实体类"></a>3.3.2.实体类</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Table(name = &quot;tb_brand&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Brand</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Id</span></span><br><span class="line">    <span class="meta">@GeneratedValue(strategy = GenerationType.IDENTITY)</span></span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line">    <span class="keyword">private</span> String name;<span class="comment">// 品牌名称</span></span><br><span class="line">    <span class="keyword">private</span> String image;<span class="comment">// 品牌图片</span></span><br><span class="line">    <span class="keyword">private</span> Character letter;</span><br><span class="line">    <span class="comment">// getter setter 略</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="3-3-3-mapper"><a href="#3-3-3-mapper" class="headerlink" title="3.3.3.mapper"></a>3.3.3.mapper</h3><p>通用mapper来简化开发：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">BrandMapper</span> <span class="keyword">extends</span> <span class="title">Mapper</span>&lt;<span class="title">Brand</span>&gt; </span>&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="3-3-4-controller"><a href="#3-3-4-controller" class="headerlink" title="3.3.4.controller"></a>3.3.4.controller</h3><p>编写controller先思考四个问题，这次没有前端代码，需要我们自己来设定</p>
<ul>
<li><p>请求方式：查询，肯定是Get</p>
</li>
<li><p>请求路径：分页查询，/brand/page</p>
</li>
<li><p>请求参数：根据我们刚才编写的页面，有分页功能，有排序功能，有搜索过滤功能，因此至少要有5个参数：</p>
<ul>
<li>page：当前页，int</li>
<li>rows：每页大小，int</li>
<li>sortBy：排序字段，String</li>
<li>desc：是否为降序，boolean</li>
<li>key：搜索关键词，String</li>
</ul>
</li>
<li><p>响应结果：分页结果一般至少需要两个数据</p>
<ul>
<li>total：总条数</li>
<li>items：当前页数据</li>
<li>totalPage：有些还需要总页数</li>
</ul>
<p>这里我们封装一个类，来表示分页结果：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PageResult</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Long total;<span class="comment">// 总条数</span></span><br><span class="line">    <span class="keyword">private</span> Long totalPage;<span class="comment">// 总页数</span></span><br><span class="line">    <span class="keyword">private</span> List&lt;T&gt; items;<span class="comment">// 当前页数据</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">PageResult</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">PageResult</span><span class="params">(Long total, List&lt;T&gt; items)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.total = total;</span><br><span class="line">        <span class="keyword">this</span>.items = items;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">PageResult</span><span class="params">(Long total, Long totalPage, List&lt;T&gt; items)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.total = total;</span><br><span class="line">        <span class="keyword">this</span>.totalPage = totalPage;</span><br><span class="line">        <span class="keyword">this</span>.items = items;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Long <span class="title">getTotal</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> total;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setTotal</span><span class="params">(Long total)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.total = total;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> List&lt;T&gt; <span class="title">getItems</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> items;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setItems</span><span class="params">(List&lt;T&gt; items)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.items = items;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Long <span class="title">getTotalPage</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> totalPage;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setTotalPage</span><span class="params">(Long totalPage)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.totalPage = totalPage;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>另外，这个PageResult以后可能在其它项目中也有需求，因此我们将其抽取到<code>ly-common</code>中，提高复用性：</p>
<p> <img src="assets/1526046620269.png" alt="1526046620269"></p>
</li>
</ul>
<p>接下来，我们编写Controller</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;brand&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BrandController</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> BrandService brandService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@GetMapping(&quot;page&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> ResponseEntity&lt;PageResult&lt;Brand&gt;&gt; queryBrandByPage(</span><br><span class="line">            <span class="meta">@RequestParam(value = &quot;page&quot;, defaultValue = &quot;1&quot;)</span> Integer page,</span><br><span class="line">            <span class="meta">@RequestParam(value = &quot;rows&quot;, defaultValue = &quot;5&quot;)</span> Integer rows,</span><br><span class="line">            <span class="meta">@RequestParam(value = &quot;sortBy&quot;, required = false)</span> String sortBy,</span><br><span class="line">            <span class="meta">@RequestParam(value = &quot;desc&quot;, defaultValue = &quot;false&quot;)</span> Boolean desc,</span><br><span class="line">            <span class="meta">@RequestParam(value = &quot;key&quot;, required = false)</span> String key) &#123;</span><br><span class="line">        PageResult&lt;Brand&gt; result = <span class="keyword">this</span>.brandService.queryBrandByPageAndSort(page,rows,sortBy,desc, key);</span><br><span class="line">        <span class="keyword">if</span> (result == <span class="keyword">null</span> || result.getItems().size() == <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> ResponseEntity&lt;&gt;(HttpStatus.NOT_FOUND);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> ResponseEntity.ok(result);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h3 id="3-3-5-Service"><a href="#3-3-5-Service" class="headerlink" title="3.3.5.Service"></a>3.3.5.Service</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BrandService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> BrandMapper brandMapper;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> PageResult&lt;Brand&gt; <span class="title">queryBrandByPageAndSort</span><span class="params">(</span></span></span><br><span class="line"><span class="function"><span class="params">            Integer page, Integer rows, String sortBy, Boolean desc, String key)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 开始分页</span></span><br><span class="line">        PageHelper.startPage(page, rows);</span><br><span class="line">        <span class="comment">// 过滤</span></span><br><span class="line">        Example example = <span class="keyword">new</span> Example(Brand.class);</span><br><span class="line">        <span class="keyword">if</span> (StringUtils.isNotBlank(key)) &#123;</span><br><span class="line">            example.createCriteria().andLike(<span class="string">&quot;name&quot;</span>, <span class="string">&quot;%&quot;</span> + key + <span class="string">&quot;%&quot;</span>)</span><br><span class="line">                    .orEqualTo(<span class="string">&quot;letter&quot;</span>, key);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (StringUtils.isNotBlank(sortBy)) &#123;</span><br><span class="line">            <span class="comment">// 排序</span></span><br><span class="line">            String orderByClause = sortBy + (desc ? <span class="string">&quot; DESC&quot;</span> : <span class="string">&quot; ASC&quot;</span>);</span><br><span class="line">            example.setOrderByClause(orderByClause);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 查询</span></span><br><span class="line">        Page&lt;Brand&gt; pageInfo = (Page&lt;Brand&gt;) brandMapper.selectByExample(example);</span><br><span class="line">        <span class="comment">// 返回结果</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> PageResult&lt;&gt;(pageInfo.getTotal(), pageInfo);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="3-3-6-测试"><a href="#3-3-6-测试" class="headerlink" title="3.3.6.测试"></a>3.3.6.测试</h3><p>通过浏览器访问试试：<a target="_blank" rel="noopener" href="http://api.leyou.com/api/item/brand/page">http://api.leyou.com/api/item/brand/page</a></p>
<p> <img src="assets/1526047708748.png" alt="1526047708748"></p>
<p>接下来，去页面请求数据并渲染</p>
<h2 id="4-4-异步查询工具axios"><a href="#4-4-异步查询工具axios" class="headerlink" title="4.4.异步查询工具axios"></a>4.4.异步查询工具axios</h2><p>异步查询数据，自然是通过ajax查询，大家首先想起的肯定是jQuery。但jQuery与MVVM的思想不吻合，而且ajax只是jQuery的一小部分。因此不可能为了发起ajax请求而去引用这么大的一个库。</p>
<h3 id="4-3-1-axios入门"><a href="#4-3-1-axios入门" class="headerlink" title="4.3.1.axios入门"></a>4.3.1.axios入门</h3><p>Vue官方推荐的ajax请求框架叫做：axios，看下demo：</p>
<p><img src="assets/1526033988251.png" alt="1526033988251"></p>
<p>axios的Get请求语法：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">axios.get(<span class="string">&quot;/item/category/list?pid=0&quot;</span>) <span class="comment">// 请求路径和请求参数拼接</span></span><br><span class="line">    .then(<span class="function"><span class="keyword">function</span>(<span class="params">resp</span>)</span>&#123;</span><br><span class="line">        <span class="comment">// 成功回调函数</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .catch(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="comment">// 失败回调函数</span></span><br><span class="line">    &#125;)</span><br><span class="line"><span class="comment">// 参数较多时，可以通过params来传递参数</span></span><br><span class="line">axios.get(<span class="string">&quot;/item/category/list&quot;</span>, &#123;</span><br><span class="line">        params:&#123;</span><br><span class="line">            pid:<span class="number">0</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function"><span class="keyword">function</span>(<span class="params">resp</span>)</span>&#123;&#125;)<span class="comment">// 成功时的回调</span></span><br><span class="line">    .catch(<span class="function"><span class="keyword">function</span>(<span class="params">error</span>)</span>&#123;&#125;)<span class="comment">// 失败时的回调</span></span><br></pre></td></tr></table></figure>

<p>axios的POST请求语法：</p>
<p>比如新增一个用户</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">axios.post(<span class="string">&quot;/user&quot;</span>,&#123;</span><br><span class="line">        name:<span class="string">&quot;Jack&quot;</span>,</span><br><span class="line">        age:<span class="number">21</span></span><br><span class="line">    &#125;)</span><br><span class="line">    .then(<span class="function"><span class="keyword">function</span>(<span class="params">resp</span>)</span>&#123;&#125;)</span><br><span class="line">    .catch(<span class="function"><span class="keyword">function</span>(<span class="params">error</span>)</span>&#123;&#125;)</span><br></pre></td></tr></table></figure>

<ul>
<li>注意，POST请求传参，不需要像GET请求那样定义一个对象，在对象的params参数中传参。post()方法的第二个参数对象，就是将来要传递的参数</li>
</ul>
<p>PUT和DELETE请求与POST请求类似</p>
<h3 id="4-3-2-axios的全局配置"><a href="#4-3-2-axios的全局配置" class="headerlink" title="4.3.2.axios的全局配置"></a>4.3.2.axios的全局配置</h3><p>而在我们的项目中，已经引入了axios，并且进行了简单的封装，在src下的http.js中：</p>
<p> <img src="assets/1526034150067.png" alt="1526034150067"></p>
<p>http.js中对axios进行了一些默认配置：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">&#x27;vue&#x27;</span></span><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">&#x27;axios&#x27;</span></span><br><span class="line"><span class="keyword">import</span> config <span class="keyword">from</span> <span class="string">&#x27;./config&#x27;</span></span><br><span class="line"><span class="comment">// config中定义的基础路径是：http://api.leyou.com/api</span></span><br><span class="line">axios.defaults.baseURL = config.api; <span class="comment">// 设置axios的基础请求路径</span></span><br><span class="line">axios.defaults.timeout = <span class="number">2000</span>; <span class="comment">// 设置axios的请求时间</span></span><br><span class="line"></span><br><span class="line">Vue.prototype.$http = axios;<span class="comment">// 将axios赋值给Vue原型的$http属性，这样所有vue实例都可使用该对象</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>

<ul>
<li><p>http.js中导入了config的配置，还记得吗？</p>
<p>  <img src="assets/1526041205846.png" alt="1526041205846"></p>
</li>
<li><p>http.js对axios进行了全局配置：<code>baseURL=config.api</code>，即<code>http://api.leyou.com/api</code>。因此以后所有用axios发起的请求，都会以这个地址作为前缀。</p>
</li>
<li><p>通过<code>Vue.property.$http = axios</code>，将<code>axios</code>赋值给了 Vue原型中的<code>$http</code>。这样以后所有的Vue实例都可以访问到$http，也就是访问到了axios了。</p>
</li>
</ul>
<h3 id="4-3-3-测试一下："><a href="#4-3-3-测试一下：" class="headerlink" title="4.3.3.测试一下："></a>4.3.3.测试一下：</h3><p>我们在组件<code>MyBrand.vue</code>的getDataFromServer方法，通过$http发起get请求，测试查询品牌的接口，看是否能获取到数据：</p>
<p>   <img src="assets/1526048079191.png" alt="1526048221750"></p>
<p>网络监视：</p>
<p> <img src="assets/1526048143014.png" alt="1526048143014"></p>
<p>控制台结果：</p>
<p><img src="assets/1526048275064.png" alt="1526048275064"></p>
<p>可以看到，在请求成功的返回结果response中，有一个data属性，里面就是真正的响应数据。</p>
<p>响应结果中与我们设计的一致，包含3个内容：</p>
<ul>
<li>total：总条数，目前是165</li>
<li>items：当前页数据</li>
<li>totalPage：总页数，我们没有返回</li>
</ul>
<h2 id="4-5-异步加载品牌数据"><a href="#4-5-异步加载品牌数据" class="headerlink" title="4.5.异步加载品牌数据"></a>4.5.异步加载品牌数据</h2><p>虽然已经通过ajax请求获取了品牌数据，但是刚才的请求没有携带任何参数，这样显然不对。我们后端接口需要5个参数：</p>
<ul>
<li>page：当前页，int</li>
<li>rows：每页大小，int</li>
<li>sortBy：排序字段，String</li>
<li>desc：是否为降序，boolean</li>
<li>key：搜索关键词，String</li>
</ul>
<p>而页面中分页信息应该是在pagination对象中，我们通过浏览器工具，查看pagination中有哪些属性：</p>
<p> <img src="assets/1526042136135.png"></p>
<p>分别是：</p>
<ul>
<li>descending：是否是降序，对应请求参数的desc</li>
<li>page：当前页，对应参数的page</li>
<li>rowsPerpage：每页大小，对应参数中的rows</li>
<li>sortBy：排序字段，对应参数的sortBy</li>
</ul>
<p>缺少一个搜索关键词，这个应该是通过v-model与输入框绑定的属性：search。这样，所有参数就都有了。</p>
<p>另外，不要忘了把查询的结果赋值给brands和totalBrands属性，Vuetify会帮我们渲染页面。</p>
<p>接下来，我们在<code>getDataFromServer</code>方法中完善请求参数：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 发起请求</span></span><br><span class="line"><span class="built_in">this</span>.$http.get(<span class="string">&quot;/item/brand/page&quot;</span>,&#123;</span><br><span class="line">        params:&#123;</span><br><span class="line">            key: <span class="built_in">this</span>.search, <span class="comment">// 搜索条件</span></span><br><span class="line">            page: <span class="built_in">this</span>.pagination.page,<span class="comment">// 当前页</span></span><br><span class="line">            rows: <span class="built_in">this</span>.pagination.rowsPerPage,<span class="comment">// 每页大小</span></span><br><span class="line">            sortBy: <span class="built_in">this</span>.pagination.sortBy,<span class="comment">// 排序字段</span></span><br><span class="line">            desc: <span class="built_in">this</span>.pagination.descending<span class="comment">// 是否降序</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;).then(<span class="function"><span class="params">resp</span> =&gt;</span> &#123; <span class="comment">// 这里使用箭头函数</span></span><br><span class="line">        <span class="comment">// 将得到的数据赋值给本地属性</span></span><br><span class="line">        <span class="built_in">this</span>.brands = resp.data.items;</span><br><span class="line">        <span class="built_in">this</span>.totalBrands = resp.data.total;</span><br><span class="line">        <span class="comment">// 完成赋值后，把加载状态赋值为false</span></span><br><span class="line">        <span class="built_in">this</span>.loading = <span class="literal">false</span>;</span><br><span class="line">    &#125;)</span><br></pre></td></tr></table></figure>

<p>查看网络请求：</p>
<p> <img src="assets/1526049810351.png" alt="1526049810351"></p>
<p>效果：</p>
<p><img src="assets/1526049139244.png" alt="1526049139244"></p>
<h2 id="4-6-完成分页和过滤"><a href="#4-6-完成分页和过滤" class="headerlink" title="4.6.完成分页和过滤"></a>4.6.完成分页和过滤</h2><h3 id="4-6-1-分页"><a href="#4-6-1-分页" class="headerlink" title="4.6.1.分页"></a>4.6.1.分页</h3><p>现在我们实现了页面加载时的第一次查询，你会发现你点击分页或搜索不会发起新的请求，怎么办？</p>
<p>虽然点击分页，不会发起请求，但是通过浏览器工具查看，会发现pagination对象的属性一直在变化：</p>
<p> <img src="assets/9.gif"></p>
<p>我们可以利用Vue的监视功能：watch，当pagination发生改变时，会调用我们的回调函数，我们在回调函数中进行数据的查询即可！</p>
<p>具体实现：</p>
<p><img src="assets/1526049643506.png" alt="1526049643506"></p>
<p>成功实现分页功能：</p>
<p><img src="assets/1526049720200.png" alt="1526049720200"></p>
<h3 id="4-6-2-过滤"><a href="#4-6-2-过滤" class="headerlink" title="4.6.2.过滤"></a>4.6.2.过滤</h3><p>分页实现了，过滤也很好实现了。过滤字段对应的是search属性，我们只要监视这个属性即可:</p>
<p> <img src="assets/1526049939985.png" alt="1526049939985"></p>
<p>查看网络请求：</p>
<p> <img src="assets/1526050032436.png" alt="1526050032436"></p>
<p>页面结果：</p>
<p><img src="assets/1526050071442.png" alt="1526050071442"></p>
<h2 id="4-7-完整代码"><a href="#4-7-完整代码" class="headerlink" title="4.7.完整代码"></a>4.7.完整代码</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;v-card&gt;</span><br><span class="line">    &lt;v-card-title&gt;</span><br><span class="line">      &lt;v-btn color&#x3D;&quot;primary&quot; @click&#x3D;&quot;addBrand&quot;&gt;新增品牌&lt;&#x2F;v-btn&gt;</span><br><span class="line">      &lt;!--搜索框，与search属性关联--&gt;</span><br><span class="line">      &lt;v-spacer&#x2F;&gt;</span><br><span class="line">      &lt;v-text-field label&#x3D;&quot;输入关键字搜索&quot; v-model.lazy&#x3D;&quot;search&quot; append-icon&#x3D;&quot;search&quot; hide-details&#x2F;&gt;</span><br><span class="line">    &lt;&#x2F;v-card-title&gt;</span><br><span class="line">    &lt;v-divider&#x2F;&gt;</span><br><span class="line">    &lt;v-data-table</span><br><span class="line">      :headers&#x3D;&quot;headers&quot;</span><br><span class="line">      :items&#x3D;&quot;brands&quot;</span><br><span class="line">      :search&#x3D;&quot;search&quot;</span><br><span class="line">      :pagination.sync&#x3D;&quot;pagination&quot;</span><br><span class="line">      :total-items&#x3D;&quot;totalBrands&quot;</span><br><span class="line">      :loading&#x3D;&quot;loading&quot;</span><br><span class="line">      class&#x3D;&quot;elevation-1&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      &lt;template slot&#x3D;&quot;items&quot; slot-scope&#x3D;&quot;props&quot;&gt;</span><br><span class="line">        &lt;td&gt;&#123;&#123; props.item.id &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.name &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&lt;img :src&#x3D;&quot;props.item.image&quot;&gt;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;text-xs-center&quot;&gt;&#123;&#123; props.item.letter &#125;&#125;&lt;&#x2F;td&gt;</span><br><span class="line">        &lt;td class&#x3D;&quot;justify-center layout&quot;&gt;</span><br><span class="line">          &lt;v-btn color&#x3D;&quot;info&quot;&gt;编辑&lt;&#x2F;v-btn&gt;</span><br><span class="line">          &lt;v-btn color&#x3D;&quot;warning&quot;&gt;删除&lt;&#x2F;v-btn&gt;</span><br><span class="line">        &lt;&#x2F;td&gt;</span><br><span class="line">      &lt;&#x2F;template&gt;</span><br><span class="line">    &lt;&#x2F;v-data-table&gt;</span><br><span class="line">  &lt;&#x2F;v-card&gt;</span><br><span class="line">&lt;&#x2F;template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">  import MyBrandForm from &#39;.&#x2F;MyBrandForm&#39;</span><br><span class="line">  export default &#123;</span><br><span class="line">    name: &quot;my-brand&quot;,</span><br><span class="line">    data() &#123;</span><br><span class="line">      return &#123;</span><br><span class="line">        search: &#39;&#39;, &#x2F;&#x2F; 搜索过滤字段</span><br><span class="line">        totalBrands: 0, &#x2F;&#x2F; 总条数</span><br><span class="line">        brands: [], &#x2F;&#x2F; 当前页品牌数据</span><br><span class="line">        loading: true, &#x2F;&#x2F; 是否在加载中</span><br><span class="line">        pagination: &#123;&#125;, &#x2F;&#x2F; 分页信息</span><br><span class="line">        headers: [</span><br><span class="line">          &#123;text: &#39;id&#39;, align: &#39;center&#39;, value: &#39;id&#39;&#125;,</span><br><span class="line">          &#123;text: &#39;名称&#39;, align: &#39;center&#39;, sortable: false, value: &#39;name&#39;&#125;,</span><br><span class="line">          &#123;text: &#39;LOGO&#39;, align: &#39;center&#39;, sortable: false, value: &#39;image&#39;&#125;,</span><br><span class="line">          &#123;text: &#39;首字母&#39;, align: &#39;center&#39;, value: &#39;letter&#39;, sortable: true,&#125;,</span><br><span class="line">          &#123;text: &#39;操作&#39;, align: &#39;center&#39;, value: &#39;id&#39;, sortable: false&#125;</span><br><span class="line">        ]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    mounted() &#123; &#x2F;&#x2F; 渲染后执行</span><br><span class="line">      &#x2F;&#x2F; 查询数据</span><br><span class="line">      this.getDataFromServer();</span><br><span class="line">    &#125;,</span><br><span class="line">    watch: &#123;</span><br><span class="line">      pagination: &#123; &#x2F;&#x2F; 监视pagination属性的变化</span><br><span class="line">        deep: true, &#x2F;&#x2F; deep为true，会监视pagination的属性及属性中的对象属性变化</span><br><span class="line">        handler() &#123;</span><br><span class="line">          &#x2F;&#x2F; 变化后的回调函数，这里我们再次调用getDataFromServer即可</span><br><span class="line">          this.getDataFromServer();</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;,</span><br><span class="line">      search: &#123; &#x2F;&#x2F; 监视搜索字段</span><br><span class="line">        handler() &#123;</span><br><span class="line">          this.getDataFromServer();</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    methods: &#123;</span><br><span class="line">      getDataFromServer() &#123; &#x2F;&#x2F; 从服务的加载数的方法。</span><br><span class="line">        &#x2F;&#x2F; 发起请求</span><br><span class="line">        this.$http.get(&quot;&#x2F;item&#x2F;brand&#x2F;page&quot;, &#123;</span><br><span class="line">          params: &#123;</span><br><span class="line">            key: this.search, &#x2F;&#x2F; 搜索条件</span><br><span class="line">            page: this.pagination.page,&#x2F;&#x2F; 当前页</span><br><span class="line">            rows: this.pagination.rowsPerPage,&#x2F;&#x2F; 每页大小</span><br><span class="line">            sortBy: this.pagination.sortBy,&#x2F;&#x2F; 排序字段</span><br><span class="line">            desc: this.pagination.descending&#x2F;&#x2F; 是否降序</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;).then(resp &#x3D;&gt; &#123; &#x2F;&#x2F; 这里使用箭头函数</span><br><span class="line">          this.brands &#x3D; resp.data.items;</span><br><span class="line">          this.totalBrands &#x3D; resp.data.total;</span><br><span class="line">          &#x2F;&#x2F; 完成赋值后，把加载状态赋值为false</span><br><span class="line">          this.loading &#x3D; false;</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;&#x2F;script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style scoped&gt;</span><br><span class="line"></span><br><span class="line">&lt;&#x2F;style&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure>





            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        Author:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/about" rel="external nofollow noreferrer">AverageJoe</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        Link:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="http://www.averagejoe.top/2018/05/28/leyou/day07-bi-ji/day07-da-jian-guan-li-xi-tong-ye-mian/">http://www.averagejoe.top/2018/05/28/leyou/day07-bi-ji/day07-da-jian-guan-li-xi-tong-ye-mian/</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        Reprint policy:
                    </i>
                </span>
                <span class="reprint-info">
                    All articles in this blog are used except for special statements
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    reprint polocy. If reproduced, please indicate source
                    <a href="/about" target="_blank">AverageJoe</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>Copied successfully, please follow the reprint policy of this article</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">more</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            <span class="chip bg-color">No tag</span>
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="twitter,facebook,google,qq,qzone,wechat,weibo,douban,linkedin" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
                <style>
    #reward {
        margin: 40px 0;
        text-align: center;
    }

    #reward .reward-link {
        font-size: 1.4rem;
        line-height: 38px;
    }

    #reward .btn-floating:hover {
        box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2), 0 5px 15px rgba(0, 0, 0, 0.2);
    }

    #rewardModal {
        width: 320px;
        height: 350px;
    }

    #rewardModal .reward-title {
        margin: 15px auto;
        padding-bottom: 5px;
    }

    #rewardModal .modal-content {
        padding: 10px;
    }

    #rewardModal .close {
        position: absolute;
        right: 15px;
        top: 15px;
        color: rgba(0, 0, 0, 0.5);
        font-size: 1.3rem;
        line-height: 20px;
        cursor: pointer;
    }

    #rewardModal .close:hover {
        color: #ef5350;
        transform: scale(1.3);
        -moz-transform:scale(1.3);
        -webkit-transform:scale(1.3);
        -o-transform:scale(1.3);
    }

    #rewardModal .reward-tabs {
        margin: 0 auto;
        width: 210px;
    }

    .reward-tabs .tabs {
        height: 38px;
        margin: 10px auto;
        padding-left: 0;
    }

    .reward-content ul {
        padding-left: 0 !important;
    }

    .reward-tabs .tabs .tab {
        height: 38px;
        line-height: 38px;
    }

    .reward-tabs .tab a {
        color: #fff;
        background-color: #ccc;
    }

    .reward-tabs .tab a:hover {
        background-color: #ccc;
        color: #fff;
    }

    .reward-tabs .wechat-tab .active {
        color: #fff !important;
        background-color: #22AB38 !important;
    }

    .reward-tabs .alipay-tab .active {
        color: #fff !important;
        background-color: #019FE8 !important;
    }

    .reward-tabs .reward-img {
        width: 210px;
        height: 210px;
    }
</style>

<div id="reward">
    <a href="#rewardModal" class="reward-link modal-trigger btn-floating btn-medium waves-effect waves-light red">赏</a>

    <!-- Modal Structure -->
    <div id="rewardModal" class="modal">
        <div class="modal-content">
            <a class="close modal-close"><i class="fas fa-times"></i></a>
            <h4 class="reward-title">你的赏识是我前进的动力</h4>
            <div class="reward-content">
                <div class="reward-tabs">
                    <ul class="tabs row">
                        <li class="tab col s6 alipay-tab waves-effect waves-light"><a href="#alipay">支付宝</a></li>
                        <li class="tab col s6 wechat-tab waves-effect waves-light"><a href="#wechat">微 信</a></li>
                    </ul>
                    <div id="alipay">
                        <img src="/medias/reward/alipay.jpg" class="reward-img" alt="支付宝打赏二维码">
                    </div>
                    <div id="wechat">
                        <img src="/medias/reward/wechat.png" class="reward-img" alt="微信打赏二维码">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    $(function () {
        $('.tabs').tabs();
    });
</script>

            
        </div>
    </div>

    

    

    

    

    
        <style>
    .valine-card {
        margin: 1.5rem auto;
    }

    .valine-card .card-content {
        padding: 20px 20px 5px 20px;
    }

    #vcomments textarea {
        box-sizing: border-box;
        background: url("/medias/comment_bg.png") 100% 100% no-repeat;
    }

    #vcomments p {
        margin: 2px 2px 10px;
        font-size: 1.05rem;
        line-height: 1.78rem;
    }

    #vcomments blockquote p {
        text-indent: 0.2rem;
    }

    #vcomments a {
        padding: 0 2px;
        color: #4cbf30;
        font-weight: 500;
        text-decoration: none;
    }

    #vcomments img {
        max-width: 100%;
        height: auto;
        cursor: pointer;
    }

    #vcomments ol li {
        list-style-type: decimal;
    }

    #vcomments ol,
    ul {
        display: block;
        padding-left: 2em;
        word-spacing: 0.05rem;
    }

    #vcomments ul li,
    ol li {
        display: list-item;
        line-height: 1.8rem;
        font-size: 1rem;
    }

    #vcomments ul li {
        list-style-type: disc;
    }

    #vcomments ul ul li {
        list-style-type: circle;
    }

    #vcomments table, th, td {
        padding: 12px 13px;
        border: 1px solid #dfe2e5;
    }

    #vcomments table, th, td {
        border: 0;
    }

    table tr:nth-child(2n), thead {
        background-color: #fafafa;
    }

    #vcomments table th {
        background-color: #f2f2f2;
        min-width: 80px;
    }

    #vcomments table td {
        min-width: 80px;
    }

    #vcomments h1 {
        font-size: 1.85rem;
        font-weight: bold;
        line-height: 2.2rem;
    }

    #vcomments h2 {
        font-size: 1.65rem;
        font-weight: bold;
        line-height: 1.9rem;
    }

    #vcomments h3 {
        font-size: 1.45rem;
        font-weight: bold;
        line-height: 1.7rem;
    }

    #vcomments h4 {
        font-size: 1.25rem;
        font-weight: bold;
        line-height: 1.5rem;
    }

    #vcomments h5 {
        font-size: 1.1rem;
        font-weight: bold;
        line-height: 1.4rem;
    }

    #vcomments h6 {
        font-size: 1rem;
        line-height: 1.3rem;
    }

    #vcomments p {
        font-size: 1rem;
        line-height: 1.5rem;
    }

    #vcomments hr {
        margin: 12px 0;
        border: 0;
        border-top: 1px solid #ccc;
    }

    #vcomments blockquote {
        margin: 15px 0;
        border-left: 5px solid #42b983;
        padding: 1rem 0.8rem 0.3rem 0.8rem;
        color: #666;
        background-color: rgba(66, 185, 131, .1);
    }

    #vcomments pre {
        font-family: monospace, monospace;
        padding: 1.2em;
        margin: .5em 0;
        background: #272822;
        overflow: auto;
        border-radius: 0.3em;
        tab-size: 4;
    }

    #vcomments code {
        font-family: monospace, monospace;
        padding: 1px 3px;
        font-size: 0.92rem;
        color: #e96900;
        background-color: #f8f8f8;
        border-radius: 2px;
    }

    #vcomments pre code {
        font-family: monospace, monospace;
        padding: 0;
        color: #e8eaf6;
        background-color: #272822;
    }

    #vcomments pre[class*="language-"] {
        padding: 1.2em;
        margin: .5em 0;
    }

    #vcomments code[class*="language-"],
    pre[class*="language-"] {
        color: #e8eaf6;
    }

    #vcomments [type="checkbox"]:not(:checked), [type="checkbox"]:checked {
        position: inherit;
        margin-left: -1.3rem;
        margin-right: 0.4rem;
        margin-top: -1px;
        vertical-align: middle;
        left: unset;
        visibility: visible;
    }

    #vcomments b,
    strong {
        font-weight: bold;
    }

    #vcomments dfn {
        font-style: italic;
    }

    #vcomments small {
        font-size: 85%;
    }

    #vcomments cite {
        font-style: normal;
    }

    #vcomments mark {
        background-color: #fcf8e3;
        padding: .2em;
    }

    #vcomments table, th, td {
        padding: 12px 13px;
        border: 1px solid #dfe2e5;
    }

    table tr:nth-child(2n), thead {
        background-color: #fafafa;
    }

    #vcomments table th {
        background-color: #f2f2f2;
        min-width: 80px;
    }

    #vcomments table td {
        min-width: 80px;
    }

    #vcomments [type="checkbox"]:not(:checked), [type="checkbox"]:checked {
        position: inherit;
        margin-left: -1.3rem;
        margin-right: 0.4rem;
        margin-top: -1px;
        vertical-align: middle;
        left: unset;
        visibility: visible;
    }
</style>

<div class="card valine-card" data-aos="fade-up">
    <div class="comment_headling" style="font-size: 20px; font-weight: 700; position: relative; padding-left: 20px; top: 15px; padding-bottom: 5px;">
        <i class="fas fa-comments fa-fw" aria-hidden="true"></i>
        <span>评论</span>
    </div>
    <div id="vcomments" class="card-content" style="display: grid">
    </div>
</div>

<script src="/libs/valine/av-min.js"></script>
<script src="/libs/valine/Valine.min.js"></script>
<script>
    new Valine({
        el: '#vcomments',
        appId: 'BhOC9gMKAfPsRTjqr679tX7A-gzGzoHsz',
        appKey: 'xb9C1I9k62m6AJvin0UWGhSr',
        notify: 'false' === 'true',
        verify: 'false' === 'true',
        visitor: 'true' === 'true',
        avatar: 'mm',
        pageSize: '10',
        lang: 'en',
        placeholder: 'just go go'
    });
</script>

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="fas fa-chevron-left"></i>&nbsp;Previous</div>
            <div class="card">
                <a href="/2018/07/25/leyou/day05-bi-ji/day05-vue-ru-men/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/0.jpg" class="responsive-img" alt="">
                        
                        <span class="card-title"></span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            学习目标
会创建Vue实例，知道Vue的常见属性
会使用Vue的生命周期的钩子函数
会使用vue常见指令
会使用vue计算属性和watch监控
会编写Vue组件
掌握组件间通信
了解vue-router使用
了解webpack使用
会使用v
                        
                    </div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="far fa-clock fa-fw icon-date"></i>2018-07-25
                        </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-user fa-fw"></i>
                            AverageJoe
                            
                        </span>
                    </div>
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                Current&nbsp;<i class="far fa-dot-circle"></i>
            </div>
            <div class="card">
                <a href="/2018/05/28/leyou/day07-bi-ji/day07-da-jian-guan-li-xi-tong-ye-mian/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/0.jpg" class="responsive-img" alt="">
                        
                        <span class="card-title"></span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            0.学习目标
使用资料搭建后台系统
会使用nginx进行反向代理
实现商品分类查询功能
掌握cors解决跨域
实现品牌查询功能

1.使用域名访问本地项目1.1.统一环境我们现在访问页面使用的是：http://localhost:9001

                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2018-05-28
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-user fa-fw"></i>
                            AverageJoe
                            
                        </span>
                    </div>
                </div>

                
            </div>
        </div>
        
    </div>
</article>

</div>



<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/libs/codeBlock/codeShrink.js"></script>


<!-- 代码块折行 -->

<style type="text/css">
code[class*="language-"], pre[class*="language-"] { white-space: pre !important; }
</style>


    </div>
    <div id="toc-aside" class="expanded col l3 hide-on-med-and-down">
        <div class="toc-widget">
            <div class="toc-title"><i class="far fa-list-alt"></i>&nbsp;&nbsp;TOC</div>
            <div id="toc-content"></div>
        </div>
    </div>
</div>

<!-- TOC 悬浮按钮. -->

<div id="floating-toc-btn" class="hide-on-med-and-down">
    <a class="btn-floating btn-large bg-color">
        <i class="fas fa-list-ul"></i>
    </a>
</div>


<script src="/libs/tocbot/tocbot.min.js"></script>
<script>
    $(function () {
        tocbot.init({
            tocSelector: '#toc-content',
            contentSelector: '#articleContent',
            headingsOffset: -($(window).height() * 0.4 - 45),
            collapseDepth: Number('0'),
            headingSelector: 'h2, h3, h4'
        });

        // modify the toc link href to support Chinese.
        let i = 0;
        let tocHeading = 'toc-heading-';
        $('#toc-content a').each(function () {
            $(this).attr('href', '#' + tocHeading + (++i));
        });

        // modify the heading title id to support Chinese.
        i = 0;
        $('#articleContent').children('h2, h3, h4').each(function () {
            $(this).attr('id', tocHeading + (++i));
        });

        // Set scroll toc fixed.
        let tocHeight = parseInt($(window).height() * 0.4 - 64);
        let $tocWidget = $('.toc-widget');
        $(window).scroll(function () {
            let scroll = $(window).scrollTop();
            /* add post toc fixed. */
            if (scroll > tocHeight) {
                $tocWidget.addClass('toc-fixed');
            } else {
                $tocWidget.removeClass('toc-fixed');
            }
        });

        
        /* 修复文章卡片 div 的宽度. */
        let fixPostCardWidth = function (srcId, targetId) {
            let srcDiv = $('#' + srcId);
            if (srcDiv.length === 0) {
                return;
            }

            let w = srcDiv.width();
            if (w >= 450) {
                w = w + 21;
            } else if (w >= 350 && w < 450) {
                w = w + 18;
            } else if (w >= 300 && w < 350) {
                w = w + 16;
            } else {
                w = w + 14;
            }
            $('#' + targetId).width(w);
        };

        // 切换TOC目录展开收缩的相关操作.
        const expandedClass = 'expanded';
        let $tocAside = $('#toc-aside');
        let $mainContent = $('#main-content');
        $('#floating-toc-btn .btn-floating').click(function () {
            if ($tocAside.hasClass(expandedClass)) {
                $tocAside.removeClass(expandedClass).hide();
                $mainContent.removeClass('l9');
            } else {
                $tocAside.addClass(expandedClass).show();
                $mainContent.addClass('l9');
            }
            fixPostCardWidth('artDetail', 'prenext-posts');
        });
        
    });
</script>

    

</main>




    <footer class="page-footer bg-color">
    
        <link rel="stylesheet" href="/libs/aplayer/APlayer.min.css">
<style>
    .aplayer .aplayer-lrc p {
        
        display: none;
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        display: none;
        
        font-size: 15px;
        color: #42b983;
    }

    
    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
        left: -66px !important;
    }

    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
        left: 0px !important;
    }

    
</style>
<div class="">
    
    <div class="row">
        <meting-js class="col l8 offset-l2 m10 offset-m1 s12"
                   server="netease"
                   type="playlist"
                   id="503838841"
                   fixed='true'
                   autoplay='false'
                   theme='#42b983'
                   loop='all'
                   order='random'
                   preload='auto'
                   volume='0.7'
                   list-folded='true'
        >
        </meting-js>
    </div>
</div>

<script src="/libs/aplayer/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>

    
    <div class="container row center-align" style="margin-bottom: 0px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            <span id="year">2019</span>
            <a href="/about" target="_blank">AverageJoe</a>
            |&nbsp;Powered by&nbsp;<a href="#" target="_blank">AverageJoe</a>
            |&nbsp;Theme&nbsp;<a href="#" target="_blank">Matery</a>
            <br>
            
            &nbsp;<i class="fas fa-chart-area"></i>&nbsp;站点总字数:&nbsp;<span
                class="white-color">213.1k</span>&nbsp;字
            
            
            
            
            
            
            <span id="busuanzi_container_site_pv">
                |&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;<span id="busuanzi_value_site_pv"
                    class="white-color"></span>&nbsp;次
            </span>
            
            
            <span id="busuanzi_container_site_uv">
                |&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;<span id="busuanzi_value_site_uv"
                    class="white-color"></span>&nbsp;人
            </span>
            
            <br>
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">


    <a href="mailto:1533360044@qq.com" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=1533360044" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 1533360044" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







    <a href="/atom.xml" class="tooltipped" target="_blank" data-tooltip="RSS 订阅" data-position="top" data-delay="50">
        <i class="fas fa-rss"></i>
    </a>

</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;Search</span>
            <input type="search" id="searchInput" name="s" placeholder="Please enter a search keyword"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script src="/js/search.js"></script>
<script type="text/javascript">
$(function () {
    searchFunc("/search.xml", 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/libs/materialize/materialize.min.js"></script>
    <script src="/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/libs/aos/aos.js"></script>
    <script src="/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/js/matery.js"></script>

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    <script src="/libs/others/clicklove.js" async="async"></script>
    
    
    <script async src="/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    

    

    

    
    <script src="/libs/instantpage/instantpage.js" type="module"></script>
    
	

	<div id="weather-v2-plugin-simple"></div>
<script>
WIDGET = {
  CONFIG: {
    "modules": "0124",
    "background": 1,
    "tmpColor": "FFFFFF",
    "tmpSize": 16,
    "cityColor": "FFFFFF",
    "citySize": 16,
    "aqiSize": 16,
    "weatherIconSize": 24,
    "alertIconSize": 18,
    "padding": "10px 10px 10px 10px",
    "shadow": "1",
    "language": "auto",
    "borderRadius": 5,
    "fixed": "false",
    "vertical": "middle",
    "horizontal": "center",
    "key": "XZgo8dbNqo"
  }
}
</script>
<script src="https://apip.weatherdt.com/simple/static/js/weather-simple-common.js?v=2.0"></script>
<script src="/js/cursor.js"></script>
</body>

</html>
